├── License.txt
├── README
├── dissector.py
├── documentation.pdf
├── ftp.py
├── http.py
├── imap.py
├── irc.py
├── pop.py
├── sip.py
├── smtp.py
├── ssh.py
├── telnet.py
└── usedissector.py
/License.txt:
--------------------------------------------------------------------------------
1 | Dissectors is copyrighted by Abdulellah Alsaheel and is licensed under
2 | the following GNU General Public License version 3.
3 |
4 | GNU GENERAL PUBLIC LICENSE
5 | Version 3, 29 June 2007
6 |
7 | Copyright (C) 2007 Free Software Foundation, Inc.
8 | Everyone is permitted to copy and distribute verbatim copies
9 | of this license document, but changing it is not allowed.
10 |
11 | Preamble
12 |
13 | The GNU General Public License is a free, copyleft license for
14 | software and other kinds of works.
15 |
16 | The licenses for most software and other practical works are designed
17 | to take away your freedom to share and change the works. By contrast,
18 | the GNU General Public License is intended to guarantee your freedom to
19 | share and change all versions of a program--to make sure it remains free
20 | software for all its users. We, the Free Software Foundation, use the
21 | GNU General Public License for most of our software; it applies also to
22 | any other work released this way by its authors. You can apply it to
23 | your programs, too.
24 |
25 | When we speak of free software, we are referring to freedom, not
26 | price. Our General Public Licenses are designed to make sure that you
27 | have the freedom to distribute copies of free software (and charge for
28 | them if you wish), that you receive source code or can get it if you
29 | want it, that you can change the software or use pieces of it in new
30 | free programs, and that you know you can do these things.
31 |
32 | To protect your rights, we need to prevent others from denying you
33 | these rights or asking you to surrender the rights. Therefore, you have
34 | certain responsibilities if you distribute copies of the software, or if
35 | you modify it: responsibilities to respect the freedom of others.
36 |
37 | For example, if you distribute copies of such a program, whether
38 | gratis or for a fee, you must pass on to the recipients the same
39 | freedoms that you received. You must make sure that they, too, receive
40 | or can get the source code. And you must show them these terms so they
41 | know their rights.
42 |
43 | Developers that use the GNU GPL protect your rights with two steps:
44 | (1) assert copyright on the software, and (2) offer you this License
45 | giving you legal permission to copy, distribute and/or modify it.
46 |
47 | For the developers' and authors' protection, the GPL clearly explains
48 | that there is no warranty for this free software. For both users' and
49 | authors' sake, the GPL requires that modified versions be marked as
50 | changed, so that their problems will not be attributed erroneously to
51 | authors of previous versions.
52 |
53 | Some devices are designed to deny users access to install or run
54 | modified versions of the software inside them, although the manufacturer
55 | can do so. This is fundamentally incompatible with the aim of
56 | protecting users' freedom to change the software. The systematic
57 | pattern of such abuse occurs in the area of products for individuals to
58 | use, which is precisely where it is most unacceptable. Therefore, we
59 | have designed this version of the GPL to prohibit the practice for those
60 | products. If such problems arise substantially in other domains, we
61 | stand ready to extend this provision to those domains in future versions
62 | of the GPL, as needed to protect the freedom of users.
63 |
64 | Finally, every program is threatened constantly by software patents.
65 | States should not allow patents to restrict development and use of
66 | software on general-purpose computers, but in those that do, we wish to
67 | avoid the special danger that patents applied to a free program could
68 | make it effectively proprietary. To prevent this, the GPL assures that
69 | patents cannot be used to render the program non-free.
70 |
71 | The precise terms and conditions for copying, distribution and
72 | modification follow.
73 |
74 | TERMS AND CONDITIONS
75 |
76 | 0. Definitions.
77 |
78 | "This License" refers to version 3 of the GNU General Public License.
79 |
80 | "Copyright" also means copyright-like laws that apply to other kinds of
81 | works, such as semiconductor masks.
82 |
83 | "The Program" refers to any copyrightable work licensed under this
84 | License. Each licensee is addressed as "you". "Licensees" and
85 | "recipients" may be individuals or organizations.
86 |
87 | To "modify" a work means to copy from or adapt all or part of the work
88 | in a fashion requiring copyright permission, other than the making of an
89 | exact copy. The resulting work is called a "modified version" of the
90 | earlier work or a work "based on" the earlier work.
91 |
92 | A "covered work" means either the unmodified Program or a work based
93 | on the Program.
94 |
95 | To "propagate" a work means to do anything with it that, without
96 | permission, would make you directly or secondarily liable for
97 | infringement under applicable copyright law, except executing it on a
98 | computer or modifying a private copy. Propagation includes copying,
99 | distribution (with or without modification), making available to the
100 | public, and in some countries other activities as well.
101 |
102 | To "convey" a work means any kind of propagation that enables other
103 | parties to make or receive copies. Mere interaction with a user through
104 | a computer network, with no transfer of a copy, is not conveying.
105 |
106 | An interactive user interface displays "Appropriate Legal Notices"
107 | to the extent that it includes a convenient and prominently visible
108 | feature that (1) displays an appropriate copyright notice, and (2)
109 | tells the user that there is no warranty for the work (except to the
110 | extent that warranties are provided), that licensees may convey the
111 | work under this License, and how to view a copy of this License. If
112 | the interface presents a list of user commands or options, such as a
113 | menu, a prominent item in the list meets this criterion.
114 |
115 | 1. Source Code.
116 |
117 | The "source code" for a work means the preferred form of the work
118 | for making modifications to it. "Object code" means any non-source
119 | form of a work.
120 |
121 | A "Standard Interface" means an interface that either is an official
122 | standard defined by a recognized standards body, or, in the case of
123 | interfaces specified for a particular programming language, one that
124 | is widely used among developers working in that language.
125 |
126 | The "System Libraries" of an executable work include anything, other
127 | than the work as a whole, that (a) is included in the normal form of
128 | packaging a Major Component, but which is not part of that Major
129 | Component, and (b) serves only to enable use of the work with that
130 | Major Component, or to implement a Standard Interface for which an
131 | implementation is available to the public in source code form. A
132 | "Major Component", in this context, means a major essential component
133 | (kernel, window system, and so on) of the specific operating system
134 | (if any) on which the executable work runs, or a compiler used to
135 | produce the work, or an object code interpreter used to run it.
136 |
137 | The "Corresponding Source" for a work in object code form means all
138 | the source code needed to generate, install, and (for an executable
139 | work) run the object code and to modify the work, including scripts to
140 | control those activities. However, it does not include the work's
141 | System Libraries, or general-purpose tools or generally available free
142 | programs which are used unmodified in performing those activities but
143 | which are not part of the work. For example, Corresponding Source
144 | includes interface definition files associated with source files for
145 | the work, and the source code for shared libraries and dynamically
146 | linked subprograms that the work is specifically designed to require,
147 | such as by intimate data communication or control flow between those
148 | subprograms and other parts of the work.
149 |
150 | The Corresponding Source need not include anything that users
151 | can regenerate automatically from other parts of the Corresponding
152 | Source.
153 |
154 | The Corresponding Source for a work in source code form is that
155 | same work.
156 |
157 | 2. Basic Permissions.
158 |
159 | All rights granted under this License are granted for the term of
160 | copyright on the Program, and are irrevocable provided the stated
161 | conditions are met. This License explicitly affirms your unlimited
162 | permission to run the unmodified Program. The output from running a
163 | covered work is covered by this License only if the output, given its
164 | content, constitutes a covered work. This License acknowledges your
165 | rights of fair use or other equivalent, as provided by copyright law.
166 |
167 | You may make, run and propagate covered works that you do not
168 | convey, without conditions so long as your license otherwise remains
169 | in force. You may convey covered works to others for the sole purpose
170 | of having them make modifications exclusively for you, or provide you
171 | with facilities for running those works, provided that you comply with
172 | the terms of this License in conveying all material for which you do
173 | not control copyright. Those thus making or running the covered works
174 | for you must do so exclusively on your behalf, under your direction
175 | and control, on terms that prohibit them from making any copies of
176 | your copyrighted material outside their relationship with you.
177 |
178 | Conveying under any other circumstances is permitted solely under
179 | the conditions stated below. Sublicensing is not allowed; section 10
180 | makes it unnecessary.
181 |
182 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
183 |
184 | No covered work shall be deemed part of an effective technological
185 | measure under any applicable law fulfilling obligations under article
186 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
187 | similar laws prohibiting or restricting circumvention of such
188 | measures.
189 |
190 | When you convey a covered work, you waive any legal power to forbid
191 | circumvention of technological measures to the extent such circumvention
192 | is effected by exercising rights under this License with respect to
193 | the covered work, and you disclaim any intention to limit operation or
194 | modification of the work as a means of enforcing, against the work's
195 | users, your or third parties' legal rights to forbid circumvention of
196 | technological measures.
197 |
198 | 4. Conveying Verbatim Copies.
199 |
200 | You may convey verbatim copies of the Program's source code as you
201 | receive it, in any medium, provided that you conspicuously and
202 | appropriately publish on each copy an appropriate copyright notice;
203 | keep intact all notices stating that this License and any
204 | non-permissive terms added in accord with section 7 apply to the code;
205 | keep intact all notices of the absence of any warranty; and give all
206 | recipients a copy of this License along with the Program.
207 |
208 | You may charge any price or no price for each copy that you convey,
209 | and you may offer support or warranty protection for a fee.
210 |
211 | 5. Conveying Modified Source Versions.
212 |
213 | You may convey a work based on the Program, or the modifications to
214 | produce it from the Program, in the form of source code under the
215 | terms of section 4, provided that you also meet all of these conditions:
216 |
217 | a) The work must carry prominent notices stating that you modified
218 | it, and giving a relevant date.
219 |
220 | b) The work must carry prominent notices stating that it is
221 | released under this License and any conditions added under section
222 | 7. This requirement modifies the requirement in section 4 to
223 | "keep intact all notices".
224 |
225 | c) You must license the entire work, as a whole, under this
226 | License to anyone who comes into possession of a copy. This
227 | License will therefore apply, along with any applicable section 7
228 | additional terms, to the whole of the work, and all its parts,
229 | regardless of how they are packaged. This License gives no
230 | permission to license the work in any other way, but it does not
231 | invalidate such permission if you have separately received it.
232 |
233 | d) If the work has interactive user interfaces, each must display
234 | Appropriate Legal Notices; however, if the Program has interactive
235 | interfaces that do not display Appropriate Legal Notices, your
236 | work need not make them do so.
237 |
238 | A compilation of a covered work with other separate and independent
239 | works, which are not by their nature extensions of the covered work,
240 | and which are not combined with it such as to form a larger program,
241 | in or on a volume of a storage or distribution medium, is called an
242 | "aggregate" if the compilation and its resulting copyright are not
243 | used to limit the access or legal rights of the compilation's users
244 | beyond what the individual works permit. Inclusion of a covered work
245 | in an aggregate does not cause this License to apply to the other
246 | parts of the aggregate.
247 |
248 | 6. Conveying Non-Source Forms.
249 |
250 | You may convey a covered work in object code form under the terms
251 | of sections 4 and 5, provided that you also convey the
252 | machine-readable Corresponding Source under the terms of this License,
253 | in one of these ways:
254 |
255 | a) Convey the object code in, or embodied in, a physical product
256 | (including a physical distribution medium), accompanied by the
257 | Corresponding Source fixed on a durable physical medium
258 | customarily used for software interchange.
259 |
260 | b) Convey the object code in, or embodied in, a physical product
261 | (including a physical distribution medium), accompanied by a
262 | written offer, valid for at least three years and valid for as
263 | long as you offer spare parts or customer support for that product
264 | model, to give anyone who possesses the object code either (1) a
265 | copy of the Corresponding Source for all the software in the
266 | product that is covered by this License, on a durable physical
267 | medium customarily used for software interchange, for a price no
268 | more than your reasonable cost of physically performing this
269 | conveying of source, or (2) access to copy the
270 | Corresponding Source from a network server at no charge.
271 |
272 | c) Convey individual copies of the object code with a copy of the
273 | written offer to provide the Corresponding Source. This
274 | alternative is allowed only occasionally and noncommercially, and
275 | only if you received the object code with such an offer, in accord
276 | with subsection 6b.
277 |
278 | d) Convey the object code by offering access from a designated
279 | place (gratis or for a charge), and offer equivalent access to the
280 | Corresponding Source in the same way through the same place at no
281 | further charge. You need not require recipients to copy the
282 | Corresponding Source along with the object code. If the place to
283 | copy the object code is a network server, the Corresponding Source
284 | may be on a different server (operated by you or a third party)
285 | that supports equivalent copying facilities, provided you maintain
286 | clear directions next to the object code saying where to find the
287 | Corresponding Source. Regardless of what server hosts the
288 | Corresponding Source, you remain obligated to ensure that it is
289 | available for as long as needed to satisfy these requirements.
290 |
291 | e) Convey the object code using peer-to-peer transmission, provided
292 | you inform other peers where the object code and Corresponding
293 | Source of the work are being offered to the general public at no
294 | charge under subsection 6d.
295 |
296 | A separable portion of the object code, whose source code is excluded
297 | from the Corresponding Source as a System Library, need not be
298 | included in conveying the object code work.
299 |
300 | A "User Product" is either (1) a "consumer product", which means any
301 | tangible personal property which is normally used for personal, family,
302 | or household purposes, or (2) anything designed or sold for incorporation
303 | into a dwelling. In determining whether a product is a consumer product,
304 | doubtful cases shall be resolved in favor of coverage. For a particular
305 | product received by a particular user, "normally used" refers to a
306 | typical or common use of that class of product, regardless of the status
307 | of the particular user or of the way in which the particular user
308 | actually uses, or expects or is expected to use, the product. A product
309 | is a consumer product regardless of whether the product has substantial
310 | commercial, industrial or non-consumer uses, unless such uses represent
311 | the only significant mode of use of the product.
312 |
313 | "Installation Information" for a User Product means any methods,
314 | procedures, authorization keys, or other information required to install
315 | and execute modified versions of a covered work in that User Product from
316 | a modified version of its Corresponding Source. The information must
317 | suffice to ensure that the continued functioning of the modified object
318 | code is in no case prevented or interfered with solely because
319 | modification has been made.
320 |
321 | If you convey an object code work under this section in, or with, or
322 | specifically for use in, a User Product, and the conveying occurs as
323 | part of a transaction in which the right of possession and use of the
324 | User Product is transferred to the recipient in perpetuity or for a
325 | fixed term (regardless of how the transaction is characterized), the
326 | Corresponding Source conveyed under this section must be accompanied
327 | by the Installation Information. But this requirement does not apply
328 | if neither you nor any third party retains the ability to install
329 | modified object code on the User Product (for example, the work has
330 | been installed in ROM).
331 |
332 | The requirement to provide Installation Information does not include a
333 | requirement to continue to provide support service, warranty, or updates
334 | for a work that has been modified or installed by the recipient, or for
335 | the User Product in which it has been modified or installed. Access to a
336 | network may be denied when the modification itself materially and
337 | adversely affects the operation of the network or violates the rules and
338 | protocols for communication across the network.
339 |
340 | Corresponding Source conveyed, and Installation Information provided,
341 | in accord with this section must be in a format that is publicly
342 | documented (and with an implementation available to the public in
343 | source code form), and must require no special password or key for
344 | unpacking, reading or copying.
345 |
346 | 7. Additional Terms.
347 |
348 | "Additional permissions" are terms that supplement the terms of this
349 | License by making exceptions from one or more of its conditions.
350 | Additional permissions that are applicable to the entire Program shall
351 | be treated as though they were included in this License, to the extent
352 | that they are valid under applicable law. If additional permissions
353 | apply only to part of the Program, that part may be used separately
354 | under those permissions, but the entire Program remains governed by
355 | this License without regard to the additional permissions.
356 |
357 | When you convey a copy of a covered work, you may at your option
358 | remove any additional permissions from that copy, or from any part of
359 | it. (Additional permissions may be written to require their own
360 | removal in certain cases when you modify the work.) You may place
361 | additional permissions on material, added by you to a covered work,
362 | for which you have or can give appropriate copyright permission.
363 |
364 | Notwithstanding any other provision of this License, for material you
365 | add to a covered work, you may (if authorized by the copyright holders of
366 | that material) supplement the terms of this License with terms:
367 |
368 | a) Disclaiming warranty or limiting liability differently from the
369 | terms of sections 15 and 16 of this License; or
370 |
371 | b) Requiring preservation of specified reasonable legal notices or
372 | author attributions in that material or in the Appropriate Legal
373 | Notices displayed by works containing it; or
374 |
375 | c) Prohibiting misrepresentation of the origin of that material, or
376 | requiring that modified versions of such material be marked in
377 | reasonable ways as different from the original version; or
378 |
379 | d) Limiting the use for publicity purposes of names of licensors or
380 | authors of the material; or
381 |
382 | e) Declining to grant rights under trademark law for use of some
383 | trade names, trademarks, or service marks; or
384 |
385 | f) Requiring indemnification of licensors and authors of that
386 | material by anyone who conveys the material (or modified versions of
387 | it) with contractual assumptions of liability to the recipient, for
388 | any liability that these contractual assumptions directly impose on
389 | those licensors and authors.
390 |
391 | All other non-permissive additional terms are considered "further
392 | restrictions" within the meaning of section 10. If the Program as you
393 | received it, or any part of it, contains a notice stating that it is
394 | governed by this License along with a term that is a further
395 | restriction, you may remove that term. If a license document contains
396 | a further restriction but permits relicensing or conveying under this
397 | License, you may add to a covered work material governed by the terms
398 | of that license document, provided that the further restriction does
399 | not survive such relicensing or conveying.
400 |
401 | If you add terms to a covered work in accord with this section, you
402 | must place, in the relevant source files, a statement of the
403 | additional terms that apply to those files, or a notice indicating
404 | where to find the applicable terms.
405 |
406 | Additional terms, permissive or non-permissive, may be stated in the
407 | form of a separately written license, or stated as exceptions;
408 | the above requirements apply either way.
409 |
410 | 8. Termination.
411 |
412 | You may not propagate or modify a covered work except as expressly
413 | provided under this License. Any attempt otherwise to propagate or
414 | modify it is void, and will automatically terminate your rights under
415 | this License (including any patent licenses granted under the third
416 | paragraph of section 11).
417 |
418 | However, if you cease all violation of this License, then your
419 | license from a particular copyright holder is reinstated (a)
420 | provisionally, unless and until the copyright holder explicitly and
421 | finally terminates your license, and (b) permanently, if the copyright
422 | holder fails to notify you of the violation by some reasonable means
423 | prior to 60 days after the cessation.
424 |
425 | Moreover, your license from a particular copyright holder is
426 | reinstated permanently if the copyright holder notifies you of the
427 | violation by some reasonable means, this is the first time you have
428 | received notice of violation of this License (for any work) from that
429 | copyright holder, and you cure the violation prior to 30 days after
430 | your receipt of the notice.
431 |
432 | Termination of your rights under this section does not terminate the
433 | licenses of parties who have received copies or rights from you under
434 | this License. If your rights have been terminated and not permanently
435 | reinstated, you do not qualify to receive new licenses for the same
436 | material under section 10.
437 |
438 | 9. Acceptance Not Required for Having Copies.
439 |
440 | You are not required to accept this License in order to receive or
441 | run a copy of the Program. Ancillary propagation of a covered work
442 | occurring solely as a consequence of using peer-to-peer transmission
443 | to receive a copy likewise does not require acceptance. However,
444 | nothing other than this License grants you permission to propagate or
445 | modify any covered work. These actions infringe copyright if you do
446 | not accept this License. Therefore, by modifying or propagating a
447 | covered work, you indicate your acceptance of this License to do so.
448 |
449 | 10. Automatic Licensing of Downstream Recipients.
450 |
451 | Each time you convey a covered work, the recipient automatically
452 | receives a license from the original licensors, to run, modify and
453 | propagate that work, subject to this License. You are not responsible
454 | for enforcing compliance by third parties with this License.
455 |
456 | An "entity transaction" is a transaction transferring control of an
457 | organization, or substantially all assets of one, or subdividing an
458 | organization, or merging organizations. If propagation of a covered
459 | work results from an entity transaction, each party to that
460 | transaction who receives a copy of the work also receives whatever
461 | licenses to the work the party's predecessor in interest had or could
462 | give under the previous paragraph, plus a right to possession of the
463 | Corresponding Source of the work from the predecessor in interest, if
464 | the predecessor has it or can get it with reasonable efforts.
465 |
466 | You may not impose any further restrictions on the exercise of the
467 | rights granted or affirmed under this License. For example, you may
468 | not impose a license fee, royalty, or other charge for exercise of
469 | rights granted under this License, and you may not initiate litigation
470 | (including a cross-claim or counterclaim in a lawsuit) alleging that
471 | any patent claim is infringed by making, using, selling, offering for
472 | sale, or importing the Program or any portion of it.
473 |
474 | 11. Patents.
475 |
476 | A "contributor" is a copyright holder who authorizes use under this
477 | License of the Program or a work on which the Program is based. The
478 | work thus licensed is called the contributor's "contributor version".
479 |
480 | A contributor's "essential patent claims" are all patent claims
481 | owned or controlled by the contributor, whether already acquired or
482 | hereafter acquired, that would be infringed by some manner, permitted
483 | by this License, of making, using, or selling its contributor version,
484 | but do not include claims that would be infringed only as a
485 | consequence of further modification of the contributor version. For
486 | purposes of this definition, "control" includes the right to grant
487 | patent sublicenses in a manner consistent with the requirements of
488 | this License.
489 |
490 | Each contributor grants you a non-exclusive, worldwide, royalty-free
491 | patent license under the contributor's essential patent claims, to
492 | make, use, sell, offer for sale, import and otherwise run, modify and
493 | propagate the contents of its contributor version.
494 |
495 | In the following three paragraphs, a "patent license" is any express
496 | agreement or commitment, however denominated, not to enforce a patent
497 | (such as an express permission to practice a patent or covenant not to
498 | sue for patent infringement). To "grant" such a patent license to a
499 | party means to make such an agreement or commitment not to enforce a
500 | patent against the party.
501 |
502 | If you convey a covered work, knowingly relying on a patent license,
503 | and the Corresponding Source of the work is not available for anyone
504 | to copy, free of charge and under the terms of this License, through a
505 | publicly available network server or other readily accessible means,
506 | then you must either (1) cause the Corresponding Source to be so
507 | available, or (2) arrange to deprive yourself of the benefit of the
508 | patent license for this particular work, or (3) arrange, in a manner
509 | consistent with the requirements of this License, to extend the patent
510 | license to downstream recipients. "Knowingly relying" means you have
511 | actual knowledge that, but for the patent license, your conveying the
512 | covered work in a country, or your recipient's use of the covered work
513 | in a country, would infringe one or more identifiable patents in that
514 | country that you have reason to believe are valid.
515 |
516 | If, pursuant to or in connection with a single transaction or
517 | arrangement, you convey, or propagate by procuring conveyance of, a
518 | covered work, and grant a patent license to some of the parties
519 | receiving the covered work authorizing them to use, propagate, modify
520 | or convey a specific copy of the covered work, then the patent license
521 | you grant is automatically extended to all recipients of the covered
522 | work and works based on it.
523 |
524 | A patent license is "discriminatory" if it does not include within
525 | the scope of its coverage, prohibits the exercise of, or is
526 | conditioned on the non-exercise of one or more of the rights that are
527 | specifically granted under this License. You may not convey a covered
528 | work if you are a party to an arrangement with a third party that is
529 | in the business of distributing software, under which you make payment
530 | to the third party based on the extent of your activity of conveying
531 | the work, and under which the third party grants, to any of the
532 | parties who would receive the covered work from you, a discriminatory
533 | patent license (a) in connection with copies of the covered work
534 | conveyed by you (or copies made from those copies), or (b) primarily
535 | for and in connection with specific products or compilations that
536 | contain the covered work, unless you entered into that arrangement,
537 | or that patent license was granted, prior to 28 March 2007.
538 |
539 | Nothing in this License shall be construed as excluding or limiting
540 | any implied license or other defenses to infringement that may
541 | otherwise be available to you under applicable patent law.
542 |
543 | 12. No Surrender of Others' Freedom.
544 |
545 | If conditions are imposed on you (whether by court order, agreement or
546 | otherwise) that contradict the conditions of this License, they do not
547 | excuse you from the conditions of this License. If you cannot convey a
548 | covered work so as to satisfy simultaneously your obligations under this
549 | License and any other pertinent obligations, then as a consequence you may
550 | not convey it at all. For example, if you agree to terms that obligate you
551 | to collect a royalty for further conveying from those to whom you convey
552 | the Program, the only way you could satisfy both those terms and this
553 | License would be to refrain entirely from conveying the Program.
554 |
555 | 13. Use with the GNU Affero General Public License.
556 |
557 | Notwithstanding any other provision of this License, you have
558 | permission to link or combine any covered work with a work licensed
559 | under version 3 of the GNU Affero General Public License into a single
560 | combined work, and to convey the resulting work. The terms of this
561 | License will continue to apply to the part which is the covered work,
562 | but the special requirements of the GNU Affero General Public License,
563 | section 13, concerning interaction through a network will apply to the
564 | combination as such.
565 |
566 | 14. Revised Versions of this License.
567 |
568 | The Free Software Foundation may publish revised and/or new versions of
569 | the GNU General Public License from time to time. Such new versions will
570 | be similar in spirit to the present version, but may differ in detail to
571 | address new problems or concerns.
572 |
573 | Each version is given a distinguishing version number. If the
574 | Program specifies that a certain numbered version of the GNU General
575 | Public License "or any later version" applies to it, you have the
576 | option of following the terms and conditions either of that numbered
577 | version or of any later version published by the Free Software
578 | Foundation. If the Program does not specify a version number of the
579 | GNU General Public License, you may choose any version ever published
580 | by the Free Software Foundation.
581 |
582 | If the Program specifies that a proxy can decide which future
583 | versions of the GNU General Public License can be used, that proxy's
584 | public statement of acceptance of a version permanently authorizes you
585 | to choose that version for the Program.
586 |
587 | Later license versions may give you additional or different
588 | permissions. However, no additional obligations are imposed on any
589 | author or copyright holder as a result of your choosing to follow a
590 | later version.
591 |
592 | 15. Disclaimer of Warranty.
593 |
594 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
595 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
596 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
597 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
598 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
599 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
600 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
601 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
602 |
603 | 16. Limitation of Liability.
604 |
605 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
606 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
607 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
608 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
609 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
610 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
611 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
612 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
613 | SUCH DAMAGES.
614 |
615 | 17. Interpretation of Sections 15 and 16.
616 |
617 | If the disclaimer of warranty and limitation of liability provided
618 | above cannot be given local legal effect according to their terms,
619 | reviewing courts shall apply local law that most closely approximates
620 | an absolute waiver of all civil liability in connection with the
621 | Program, unless a warranty or assumption of liability accompanies a
622 | copy of the Program in return for a fee.
623 |
624 | END OF TERMS AND CONDITIONS
625 |
626 | The file UserDB.txt is copyrighted by BoB / Team PEiD distributed under the following
627 | MIT license.
628 |
629 | Permission is hereby granted, free of charge, to any person obtaining a copy of this
630 | software and associated documentation files (the "Software"), to deal in the Software
631 | without restriction, including without limitation the rights to use, copy, modify,
632 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
633 | permit persons to whom the Software is furnished to do so, subject to the following
634 | conditions:
635 |
636 | The above copyright notice and this permission notice shall be included in all copies
637 | or substantial portions of the Software.
638 |
639 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
640 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
641 | PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
642 | FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
643 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
644 | DEALINGS IN THE SOFTWARE.
645 |
646 | The file jquery.js is copyrighted by John Resig and dual licensed under the MIT or GPL
647 | Version 2 licenses (see: http://jquery.org/license).
648 |
649 | The files lightbox.js and lightbox.css are copyrighted by Lokesh Dhakar and licensed under
650 | the Creative Commons Attribution 2.5 License
651 | (see: http://creativecommons.org/licenses/by/2.5/).
652 |
653 | The files bootstrap-fileupload.js, jasny-bootstrap.js, jasny-bootstrap.min.js,
654 | jasny-bootstrap.css, jasny-bootstrap.min.css, jasny-bootstrap-responsive.css,
655 | jasny-bootstrap-responsive.min.css are copyrighted by Jasny BV and licensed under the Apache
656 | License, Version 2.0.
657 |
658 | The files bootstrap.min.js, bootstrap.min.css, bootstrap-responsive.min.css,
659 | glyphicons-halflings.png, glyphicons-halflings-white.png are copyrighted by Twitter, Inc.
660 | and licensed under the Apache License, Version 2.0.
661 |
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 | This Library:
2 | Essentially, this library has been implemented to be a part of Cuckoo Sandbox
3 | the automated malware analysis tool. This library is depend on Scapy library.
4 |
5 | The Supported protocols:
6 | 1- this library can parse (dissect) these protocols:
7 | TCP, UDP, ICMP, DNS, HTTP, FTP, IRC, SMB, SIP, TELNET, SMTP, SSH, IMAP and POP.
8 | 2- this library is aware of TCP reassembly.
9 | 3- this library is capable of recovering the downloaded files through HTTP, FTP and SMTP.
10 |
11 | for any further questions or information please contact me.
12 |
13 | cs_saheel@hotmail.com
14 | Abdulellah Alsaheel
15 |
--------------------------------------------------------------------------------
/dissector.py:
--------------------------------------------------------------------------------
1 | import json # json formatting module
2 | import binascii # this class to handle the hex/ascii converting
3 | from scapy.all import Packet, rdpcap, ConditionalField, Emph, conf
4 | '''
5 | imported files from Scapy library
6 | '''
7 | from scapy.layers.dot11 import *
8 | from scapy.layers.ir import *
9 | from scapy.layers.ppp import *
10 | from scapy.layers.gprs import *
11 | from scapy.layers.mobileip import *
12 | from scapy.layers.smb import *
13 | from scapy.layers.bluetooth import *
14 | from scapy.layers.isakmp import *
15 | from scapy.layers.radius import *
16 | from scapy.layers.hsrp import *
17 | from scapy.layers.netbios import *
18 | from scapy.layers.snmp import *
19 | from scapy.layers.dhcp6 import *
20 | from scapy.layers.l2 import *
21 | from scapy.layers.rip import *
22 | from scapy.layers.inet6 import *
23 | from scapy.layers.netflow import *
24 | from scapy.layers.tftp import *
25 | from scapy.layers.dhcp import *
26 | from scapy.layers.l2tp import *
27 | from scapy.layers.rtp import *
28 | from scapy.layers.inet import *
29 | from scapy.layers.ntp import *
30 | from scapy.layers.x509 import *
31 | from scapy.layers.dns import *
32 | from scapy.layers.llmnr import *
33 | from scapy.layers.sebek import *
34 | from scapy.layers.pflog import *
35 | from scapy.layers.dot11 import *
36 | from scapy.layers.mgcp import *
37 | from scapy.layers.skinny import *
38 | '''
39 | import the protocols classes
40 | '''
41 | from ftp import *
42 | from http import *
43 | from imap import *
44 | from irc import *
45 | from pop import *
46 | from sip import *
47 | from smtp import *
48 | from ssh import *
49 | from telnet import *
50 |
51 |
52 | def is_created_session(Src, Dst, SPort, DPort):
53 | """
54 | this method is used for purpose of tcp stream reassemble,
55 | for checking if this is a new session of not.
56 | @param Src: source ip address
57 | @param Dst: destination ip address
58 | @param SPort: source port number
59 | @param DPort: destination port number
60 | """
61 | i = 0
62 | while i < len(dissector.Dissector.preprocess_sessions):
63 | if Src == dissector.Dissector.preprocess_sessions[i][0]\
64 | and Dst == dissector.Dissector.preprocess_sessions[i][1]\
65 | and SPort == dissector.Dissector.preprocess_sessions[i][2]\
66 | and DPort == dissector.Dissector.preprocess_sessions[i][3]:
67 | return True
68 | i = i + 1
69 | return False
70 |
71 |
72 | def create_session(Src, Dst, SPort, DPort, expected_seq):
73 | """
74 | this method is used for purpose of tcp stream reassemble,
75 | for creating a new session.
76 | @param Src: source ip address
77 | @param Dst: destination ip address
78 | @param SPort: source port number
79 | @param DPort: destination port number
80 | @param stream: the initial packet
81 | @param expected_seq: sequence number
82 | """
83 | if not is_created_session(Src, Dst, SPort, DPort):
84 | dissector.Dissector.preprocess_sessions.append(\
85 | [Src, Dst, SPort, DPort, expected_seq])
86 |
87 |
88 | def build_stream(Src, Dst, SPort, DPort, stream):
89 | """
90 | this method is used for purpose of tcp stream reassemble,
91 | for appending a new packet.
92 | @param Src: source ip address
93 | @param Dst: destination ip address
94 | @param SPort: source port number
95 | @param DPort: destination port number
96 | @param stream: the current packet
97 | """
98 | i = 0
99 | while i < len(dissector.Dissector.preprocess_sessions):
100 | if Src == dissector.Dissector.preprocess_sessions[i][0]\
101 | and Dst == dissector.Dissector.preprocess_sessions[i][1] and\
102 | SPort == dissector.Dissector.preprocess_sessions[i][2] and\
103 | DPort == dissector.Dissector.preprocess_sessions[i][3]:
104 | dissector.Dissector.preprocess_sessions[i][4] =\
105 | dissector.Dissector.preprocess_sessions[i][4].append_data(\
106 | Src, Dst, SPort, DPort, stream)
107 | break
108 | i = i + 1
109 |
110 |
111 | def get_stream(Src, Dst, SPort, DPort, obj):
112 | """
113 | this method is used for purpose of tcp stream reassemble,
114 | for retrieving a stream or packet.
115 | @param Src: source ip address
116 | @param Dst: destination ip address
117 | @param SPort: source port number
118 | @param DPort: destination port number
119 | @param obj: last packet to be appended
120 | """
121 | i = 0
122 | while i < len(dissector.Dissector.sessions):
123 | if Src == dissector.Dissector.sessions[i][0] and\
124 | Dst == dissector.Dissector.sessions[i][1] and\
125 | SPort == dissector.Dissector.sessions[i][2] and\
126 | DPort == dissector.Dissector.preprocess_sessions[i][3]:
127 | if dissector.Dissector.sessions[i][4].seq == obj.seq:
128 | return dissector.Dissector.sessions[i][4].pkt
129 | i = i + 1
130 | return -1
131 |
132 |
133 | def is_stream_end(Src, Dst, SPort, DPort, obj):
134 | """
135 | this method is used for purpose of tcp stream reassemble,
136 | for checking whether if this is the last packet in the stream or not.
137 | @param Src: source ip address
138 | @param Dst: destination ip address
139 | @param SPort: source port number
140 | @param DPort: destination port number
141 | @param obj: last packet in stream.
142 | """
143 | i = 0
144 | while i < len(dissector.Dissector.sessions):
145 | if Src == dissector.Dissector.sessions[i][0] and\
146 | Dst == dissector.Dissector.sessions[i][1] and\
147 | SPort == dissector.Dissector.sessions[i][2] and\
148 | DPort == dissector.Dissector.sessions[i][3]:
149 | if dissector.Dissector.sessions[i][4].seq == obj.seq:
150 | return True
151 | i = i + 1
152 | return False
153 |
154 |
155 | def check_stream(Src, Dst, SPort, DPort, Seq, s):
156 | """
157 | this method is used for purpose of tcp stream reassemble,
158 | for checking whether if this is the last packet in the stream or not.
159 | @param Src: source ip address
160 | @param Dst: destination ip address
161 | @param SPort: source port number
162 | @param DPort: destination port number
163 | @param seq: sequence number
164 | @param s: packet payload to create a new session or to be appended in an existed session.
165 | """
166 | if not dissector.is_created_session(Src, Dst, SPort, DPort):
167 | seqn = Seq
168 | stream = dissector.Stream(s, seqn)
169 | dissector.create_session(Src, Dst, SPort, DPort, stream)
170 | elif dissector.is_created_session(Src, Dst, SPort, DPort):
171 | seqn = Seq
172 | stream = dissector.Stream(s, seqn)
173 | dissector.build_stream(Src, Dst, SPort, DPort, stream)
174 | if len(dissector.Dissector.sessions) > 0:
175 | if dissector.is_stream_end(Src, Dst, SPort, DPort, stream):
176 | s = dissector.get_stream(Src, Dst, SPort, DPort, stream)
177 | if not s == -1:
178 | return s
179 | return -1
180 |
181 |
182 | class Stream:
183 | """
184 | this class is for tcp reassembling
185 | """
186 | pkt = ""
187 | seq = -1
188 | length_of_last_packet = -1
189 | stream = False
190 |
191 | def __init__(self, pkt, seq):
192 | """
193 | this constructor is used for purpose of tcp stream reassemble,
194 | for initializing tcp packets.
195 | @param pkt: packet payload
196 | @param push: specify if push flag is true or false
197 | @param seq: sequence number
198 | """
199 | self.stream = False
200 | self.pkt = pkt
201 | self.seq = seq
202 | self.length_of_last_packet = len(pkt)
203 |
204 | def append_data(self, Src, Dst, SPort, DPort, obj):
205 | """
206 | this method is used for purpose of tcp stream reassemble,
207 | for appending a packet to an existing stream.
208 | @param Src: source ip address
209 | @param Dst: destination ip address
210 | @param SPort: source port number
211 | @param DPort: destination port number
212 | @param obj: last packet in stream.
213 | """
214 | if self.seq + self.length_of_last_packet == obj.seq:
215 | self.stream = True
216 | self.append_packet(obj.pkt)
217 | self.change_seq(obj.seq)
218 | self.length_of_last_packet = len(obj.pkt)
219 | return self
220 |
221 | def append_packet(self, pkt):
222 | """
223 | this method is used for purpose of tcp stream reassemble,
224 | for appending a packet payload to an existing stream.
225 | @param pkt: packet payload.
226 | """
227 | self.pkt = self.pkt + pkt
228 |
229 | def change_seq(self, seq):
230 | """
231 | this method is used for purpose of tcp stream reassemble,
232 | for the last packet sequence in the stream.
233 | @param seq: sequence number.
234 | """
235 | self.seq = seq
236 |
237 |
238 | def int2bin(n, count=16):
239 | """
240 | this method converts integer numbers to binary numbers
241 | @param n: the number to be converted
242 | @param count: the number of binary digits
243 | """
244 | return "".join([str((n >> y) & 1) for y in range(count-1, -1, -1)])
245 |
246 |
247 | class Dissector(Packet):
248 | """
249 | this is the main class of this library
250 | Note:
251 | implemented protocols like http,sip, (usually or sometimes) return binary
252 | data, and in some other cases return human readable data,
253 | so i have decided to make these protocols return the data represented as
254 | a hex values, you may want to have its payload in ascii too if so then
255 | use get_ascii()
256 | """
257 | packet = None
258 | type = 0
259 | preprocess_sessions = []
260 | sessions = []
261 | preprocess_done = False
262 | default_download_folder_changed = False
263 | path = ""
264 |
265 | def change_dfolder(self, path):
266 | dissector.Dissector.default_download_folder_changed = True
267 | if not path[len(path) - 1] == "/" and not path[len(path) - 1] == "\\":
268 | path = path + "/"
269 | dissector.Dissector.path = path
270 |
271 | def recalculate_seq(self):
272 | i = 0
273 | while i < len(dissector.Dissector.sessions):
274 | Dissector.sessions[i][4].seq = Dissector.sessions[i][4].seq -\
275 | Dissector.sessions[i][4].length_of_last_packet
276 | i = i + 1
277 |
278 | def get_ascii(self, hexstr):
279 | """
280 | get hex string and returns ascii chars
281 | @param hexstr: hex value in str format
282 | """
283 | return binascii.unhexlify(hexstr)
284 |
285 | def defined_protocol(self, name):
286 | if name.startswith("tcp") and name.endswith("tcp") or\
287 | name.startswith("udp") and name.endswith("udp") or\
288 | name.startswith("icmp") and name.endswith("icmp") or\
289 | name.startswith("dns") and name.endswith("dns") or\
290 | name.startswith("http") and name.endswith("http") or\
291 | name.startswith("ftp") and name.endswith("ftp") or\
292 | name.startswith("irc") and name.endswith("irc") or\
293 | name.startswith("smb") and name.endswith("smb") or\
294 | name.startswith("sip") and name.endswith("sip") or\
295 | name.startswith("telnet") and name.endswith("telnet") or\
296 | name.startswith("smtp") or name.startswith("ssh") or\
297 | name.startswith("imap") and name.endswith("imap") or\
298 | name.startswith("pop") and name.endswith("pop"):
299 | return True
300 |
301 | def clean_out(self, value):
302 | value = value.rstrip()
303 | value = value.lstrip()
304 | if value.startswith("'") and value.endswith("'"):
305 | return value[1:-1]
306 | elif value.startswith("'") and not value.endswith("'"):
307 | return value[1:]
308 | elif value.endswith("'") and not value.startswith("'"):
309 | return value[:-1]
310 | else:
311 | return value
312 |
313 | def dissect(self, packet):
314 | """
315 | this is the main method in the library, which dissects packets and
316 | returns them as a list of protocols' fields.
317 | @param pcapfile: path to a pcap/cap library
318 | """
319 | ct = conf.color_theme
320 | flds = []
321 | flds.append(ct.layer_name(packet.name))
322 |
323 | for f in packet.fields_desc:
324 | if isinstance(f, ConditionalField) and not f._evalcond(self):
325 | continue
326 | if isinstance(f, Emph) or f in conf.emph:
327 | ncol = ct.emph_field_name
328 | vcol = ct.emph_field_value
329 | else:
330 | ncol = ct.field_name
331 | vcol = ct.field_value
332 |
333 | fvalue = packet.getfieldval(f.name)
334 | flds.append((ncol(f.name), vcol(f.i2repr(self, fvalue))))
335 | return flds
336 |
337 | def is_printable(self, f):
338 | if isinstance(f, tuple) and not f[1] == "''" and not\
339 | f[1] == '' and not f[1] == "" and not f[1] == [] and not\
340 | f[1] == '[]' and not f[1] == "[]" and len(f[1]) > 0:
341 | return True
342 | return False
343 |
344 | def __getattr__(self, attr):
345 | if self.initialized:
346 | fld, v = self.getfield_and_val(attr)
347 | if fld is not None:
348 | return fld.i2h(self, v)
349 | return v
350 |
351 | def seq_analysis(self, pcapfile):
352 | """
353 | this method act as an interface for the dissect() method.
354 | and to represents the data in the required format.
355 | @param pcapfile: path to a pcap/cap library
356 | """
357 | packetslist = rdpcap(pcapfile)
358 | pktsfields = []
359 | protocols = []
360 | entry = {}
361 | recognized = False
362 | for pkt in packetslist:
363 | firstlayer = True
364 | if pkt:
365 | if firstlayer:
366 | firstlayer = False
367 | self.packet = pkt
368 | fields = self.dissect(self.packet)
369 |
370 | load = pkt
371 | while load.payload:
372 | load = load.payload
373 | self.packet = load
374 |
375 | fields = self.dissect(self.packet)
376 |
377 | if fields[0]:
378 | if fields[0] == "NoPayload":
379 | break
380 |
381 | def dissect_pkts(self, pcapfile):
382 | """
383 | this method act as an interface for the dissect() method.
384 | and to represents the data in the required format.
385 | @param pcapfile: path to a pcap/cap library
386 | """
387 | self.seq_analysis(pcapfile)
388 | Dissector.sessions = Dissector.preprocess_sessions
389 | Dissector.preprocess_sessions = []
390 | Dissector.preprocess_done = True
391 | packetslist = rdpcap(pcapfile)
392 | pktsfields = []
393 | protocols = []
394 | entry = {}
395 | recognized = False
396 | for pkt in packetslist:
397 | firstlayer = True
398 | if pkt:
399 | if firstlayer:
400 | firstlayer = False
401 | self.packet = pkt
402 | fields = self.dissect(self.packet)
403 |
404 | j = 1
405 | entry = {}
406 | while j < len(fields):
407 | if self.is_printable(fields[j]):
408 | entry[fields[j][0]] = fields[j][1]
409 | j = j + 1
410 |
411 | i = 0
412 | while i < len(protocols):
413 | if fields[0] in protocols[i]:
414 | protocols[i].append(entry)
415 | break
416 | elif fields[0] not in protocols[i] and \
417 | i == len(protocols) - 1:
418 | protocols.append([fields[0]])
419 | protocols[i + 1].append(entry)
420 | break
421 | i = i + 1
422 | if len(protocols) == 0:
423 | protocols.append([fields[0]])
424 | protocols[0].append(entry)
425 |
426 | load = pkt
427 | while load.payload:
428 | load = load.payload
429 | self.packet = load
430 |
431 | fields = self.dissect(self.packet)
432 |
433 | entry = {}
434 | if fields[0]:
435 | if fields[0] == "NoPayload":
436 | break
437 |
438 | j = 1
439 | first = True
440 | if not recognized:
441 | entry = {}
442 | while j < len(fields):
443 | if self.is_printable(fields[j]):
444 | if fields[0] == "UDP":
445 | recognized = True
446 | entry["src"] = load.underlayer.fields["src"]
447 | entry["dst"] = load.underlayer.fields["dst"]
448 | entry["sdport"] = load.fields["sport"]
449 | entry["dport"] = load.fields["dport"]
450 | if fields[0] == "TCP":
451 | recognized = True
452 | entry["src"] = load.underlayer.fields["src"]
453 | entry["dst"] = load.underlayer.fields["dst"]
454 | entry["sdport"] = load.fields["sport"]
455 | entry["dport"] = load.fields["dport"]
456 |
457 | if fields[0] == "DNS":
458 | recognized = True
459 | qdfield = None
460 | anfield = None
461 | type = None
462 | name = None
463 | pname = None
464 | found = False
465 | entry = []
466 | if load.fields["qd"]:
467 | for element in fields:
468 | if "qd" in element:
469 | qdfield = element[1]
470 | if qdfield.count("|") == 1:
471 | line = qdfield.split()
472 | for t in line:
473 | if t.startswith("qname="):
474 | found = True
475 | name = t[6:]
476 | if t.startswith("qtype="):
477 | found = True
478 | type = t[6:]
479 | if found:
480 | entry.append(\
481 | {"name": name, "type": type})
482 | found = False
483 |
484 | if qdfield.count("|") > 1:
485 | entry["name"] = []
486 | qlist = qdfield.split(" |")
487 | for record in qlist:
488 | line = record.split()
489 | for t in line:
490 | if t.startswith("qname="):
491 | found = True
492 | name = t[6:]
493 | if t.startswith("qtype="):
494 | found = True
495 | type = t[6:]
496 | if found:
497 | entry.append(\
498 | {"name": name, "type": type})
499 | found = False
500 |
501 | if load.fields["an"]:
502 | for element in fields:
503 | if "an" in element:
504 | anfield = element[1]
505 |
506 | if anfield.count("|") == 1:
507 | line = anfield.split()
508 | for t in line:
509 | if t.startswith("rrname="):
510 | found = True
511 | name = t[7:]
512 | if t.startswith("type="):
513 | found = True
514 | type = t[5:]
515 | if t.startswith("rdata="):
516 | found = True
517 | pname = t[6:]
518 | if found:
519 | entry.append(\
520 | {"name": name, "type": type, "pname": pname})
521 | found = False
522 | if anfield.count("|") > 1:
523 | alist = anfield.split(" |")
524 | for record in alist:
525 | line = record.split()
526 | for t in line:
527 | if t.startswith("rrname="):
528 | found = True
529 | name = t[7:]
530 | if t.startswith("type="):
531 | found = True
532 | type = t[5:]
533 | if t.startswith("rdata="):
534 | found = True
535 | pname = t[6:]
536 | if found:
537 | entry.append(\
538 | {"name": name[1:-2], "type": type, "pname": pname[1:-1]})
539 | found = False
540 |
541 | if isinstance(fields[0], str) and\
542 | fields[0].startswith("http"):
543 | recognized = True
544 | if isinstance(fields[j][1], str):
545 | if first and not fields[j][0][:-2] ==\
546 | "unknown-header(s)" and\
547 | not fields[j][0][:-2] == "message-body":
548 | entry[fields[j][0][:-2]] =\
549 | self.clean_out(fields[j][1][len(fields[j][0]) + 1:-1])
550 | elif first and fields[j][0][:-2] ==\
551 | "unknown-header(s)":
552 | entry[fields[j][0][:-2]] =\
553 | self.clean_out(fields[j][1])
554 | elif first and fields[j][0][:-2] ==\
555 | "message-body":
556 | entry[fields[j][0][:-2]] = fields[j][1]
557 | else:
558 | entry[fields[j][0]] =\
559 | self.clean_out(fields[j][1])
560 |
561 | if isinstance(fields[0], str) and\
562 | fields[0].startswith("sip"):
563 | recognized = True
564 | if isinstance(fields[j][1], str):
565 | if first and not fields[j][0][:-2] ==\
566 | "unknown-header(s)" and not\
567 | fields[j][0][:-2] == "message-body":
568 | entry[fields[j][0][:-2]] =\
569 | self.clean_out(fields[j][1][len(fields[j][0]) + 1:-1])
570 | elif first and fields[j][0][:-2] ==\
571 | "unknown-header(s)":
572 | entry[fields[j][0][:-2]] =\
573 | self.clean_out(fields[j][1])
574 | elif first and fields[j][0][:-2] ==\
575 | "message-body":
576 | entry[fields[j][0][:-2]] =\
577 | fields[j][1][1:-1]
578 | else:
579 | entry[fields[j][0]] = self.clean_out(\
580 | self.clean_out(fields[j][1]))
581 |
582 | if isinstance(fields[0], str) and\
583 | fields[0].startswith("smtp"):
584 | recognized = True
585 | if fields[j][0].startswith("command") and\
586 | fields[j][1].startswith("['DATA', '") and\
587 | fields[j][1].endswith("']"):
588 |
589 | entry["data"] = fields[j][1][10:-2]
590 | entry["type"] = "data"
591 | elif fields[j][0].startswith("response") and\
592 | fields[j][0].endswith("response"):
593 | result = fields[j][1]
594 | result = "[" +\
595 | result[1:-1].replace("'", '"') + "]"
596 | try:
597 | result = json.loads(result)
598 | except Exception:
599 | None
600 | entry[fields[j][0]] = result
601 | entry["type"] = "response"
602 | elif fields[j][0].startswith("command") or\
603 | fields[j][0].startswith("argument"):
604 | if isinstance(entry, dict):
605 | entry[fields[j][0]] =\
606 | fields[j][1][1:-1]
607 | if not "type" in entry:
608 | entry["type"] = "request"
609 | if j == len(fields) - 1:
610 | temp = ""
611 | if entry["type"] == "request":
612 | if "command" in entry:
613 | temp = "command: " +\
614 | entry["command"]
615 | if entry["command"] ==\
616 | "DATA":
617 | None
618 | if "argument" in entry:
619 | temp = temp +\
620 | ", argument: " + entry["argument"]
621 | if "type" in entry:
622 | temp = temp +\
623 | ", type: " + entry["type"]
624 | entry = temp
625 | elif isinstance(entry, str):
626 | if len(entry) > 0:
627 | entry = entry + ", " +\
628 | fields[j][0] + ": " + fields[j][1][1:-1]
629 | else:
630 | entry = fields[j][0] + ": " +\
631 | fields[j][1][1:-1]
632 | if j == len(fields) - 1:
633 | entry = entry + ", type: request"
634 | else:
635 | entry = entry + fields[j][0] +\
636 | ": " + fields[j][1][1:-1]
637 | if j == len(fields) - 1:
638 | entry = entry + ", type: request"
639 |
640 | if isinstance(fields[0], str) and\
641 | fields[0].startswith("ftp"):
642 | recognized = True
643 | if isinstance(entry, dict):
644 | entry = ""
645 | if len(entry) > 0:
646 | entry = entry + ", " +\
647 | fields[j][0] + ": " + self.clean_out(fields[j][1][1:-1])
648 | else:
649 | entry = entry + fields[j][0] +\
650 | ": " + self.clean_out(fields[j][1][1:-1])
651 | if j == len(fields) - 1 and\
652 | pkt.payload.payload.fields["sport"] == 21 or\
653 | pkt.payload.payload.fields["sport"] == 20:
654 | entry = entry + ", type: response"
655 | elif j == len(fields) - 1 and\
656 | pkt.payload.payload.fields["dport"] == 21 or\
657 | pkt.payload.payload.fields["dport"] == 20:
658 | entry = entry + ", type: request"
659 | if isinstance(fields[0], str) and\
660 | fields[0].startswith("imap"):
661 | recognized = True
662 | entry = entry + fields[j][1] + " "
663 | if isinstance(fields[0], str) and\
664 | fields[0].startswith("pop"):
665 | recognized = True
666 | entry = entry + fields[j][1] + " "
667 | if isinstance(fields[0], str) and\
668 | fields[0].startswith("irc"):
669 | recognized = True
670 | entry = fields[j][1][1:-1]
671 |
672 | if isinstance(fields[0], str) and\
673 | fields[0].startswith("telnet"):
674 | recognized = True
675 | entry = fields[j][1][:-1]
676 |
677 | if isinstance(fields[0], str) and\
678 | fields[0].startswith("ssh"):
679 | recognized = True
680 | entry = fields[j][1]
681 | if j == len(fields) - 1 and\
682 | pkt.payload.payload.fields["sport"] == 22:
683 | entry = entry + ", type: response"
684 | elif j == len(fields) - 1 and\
685 | pkt.payload.payload.fields["dport"] == 22:
686 | entry = entry + ", type: request"
687 |
688 | if not recognized:
689 | entry[fields[j][0]] =\
690 | self.clean_out(fields[j][1])
691 | recognized = False
692 | j = j + 1
693 |
694 | i = 0
695 | while i < len(protocols):
696 | if fields[0].lower() in protocols[i]:
697 | if len(entry) > 0:
698 | protocols[i].append(entry)
699 | break
700 | elif fields[0].lower() not in protocols[i] and \
701 | i == len(protocols) - 1:
702 | protocols.append([fields[0].lower()])
703 | if len(entry) > 0:
704 | protocols[i + 1].append(entry)
705 | break
706 | i = i + 1
707 | if len(protocols) == 0:
708 | protocols.append([fields[0].lower()])
709 | if len(entry) > 0:
710 | protocols[0].append(entry)
711 |
712 | dproto = {}
713 | i = 0
714 | for proto in protocols:
715 | if self.defined_protocol(proto[0].lower()):
716 |
717 | dproto[proto[0].lower()] = proto[1:]
718 |
719 | return dproto
720 |
--------------------------------------------------------------------------------
/documentation.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cssaheel/dissectors/cb32c5f6cb8c85b4cec9fc3aa29fb303ad826f8c/documentation.pdf
--------------------------------------------------------------------------------
/ftp.py:
--------------------------------------------------------------------------------
1 | import base64
2 | import os
3 | import string
4 | import random
5 | from scapy.packet import *
6 | from scapy.fields import *
7 | from scapy.ansmachine import *
8 | from scapy.layers.inet import *
9 | import dissector
10 |
11 |
12 | last_file = "NoName"
13 |
14 |
15 | def name_generator(size=9, chars=string.ascii_uppercase + string.digits):
16 | """
17 | this method is for generating a randndom name for the downloaded files
18 | @param size: number of random characters
19 | @param chars: type of the random characters
20 | """
21 | return ''.join(random.choice(chars) for x in range(size))
22 |
23 |
24 | def clean_file_name(name, path):
25 | """
26 | this method is for cleaning the carved file name if it has some special chars
27 | which is not allowed in most of the operating systems or if the specified folder
28 | in path variable has another file has the same name.
29 | @param name: the carved file name
30 | @param path: the directory path
31 | """
32 | ls = list(name)
33 | result = ""
34 | length = len(ls)
35 | files = os.listdir(path)
36 | if len(name) > 25 or name in files or name == "NoName":
37 | return name_generator()
38 | i = 0
39 | while i < length:
40 | if not ls[i].isdigit() and not ls[i].isalpha and not ls[i] == ".":
41 | del(ls[i])
42 | else:
43 | result = result + ls[i]
44 | i = i + 1
45 | if len(result) > 0:
46 | return result
47 | else:
48 | return name_generator()
49 |
50 |
51 | def add_file(name):
52 | """
53 | this method is for storing the carved file name.
54 | @param name: the carved file name
55 | """
56 | global last_file
57 | ls = []
58 | if "/" in name:
59 | ls = name.split("/")
60 | if len(ls) > 0:
61 | last_file = ls[len(ls) - 1]
62 |
63 |
64 | def get_file():
65 | """
66 | this method is for retrieving the stored file name
67 | """
68 | return last_file
69 |
70 | # list for maintaining the ftp data sessions
71 | ftpdatasessions = []
72 |
73 |
74 | def is_created_session(Src, Dst, SPort):
75 | """
76 | this method returns true if the ftp data session is exist
77 | @param Src: source ip address
78 | @param Dst: destination ip address
79 | @param SPort: source port number
80 | """
81 | i = 0
82 | while i < len(ftpdatasessions):
83 | if str(Src) and str(Dst) and str(SPort) in ftpdatasessions[i]:
84 | return True
85 | i = i + 1
86 | return False
87 |
88 |
89 | def create_session(Src, Dst, SPort):
90 | """
91 | this method for creating the ftp data sessions
92 | @param Src: source ip address
93 | @param Dst: destination ip address
94 | @param SPort: source port number
95 | """
96 | if not is_created_session(Src, Dst, SPort):
97 | ftpdatasessions.append([Src, Dst, SPort])
98 | return True
99 | return False
100 |
101 |
102 | def bind(Port):
103 | """
104 | ftp data sessions which get establish after do an agreement
105 | on a specific port number at the server, this port number need
106 | to be bounded by using bind_layers() method
107 | @param Port: source port number at the server side
108 | """
109 | bind_layers(TCP, FTPData, sport=int(Port))
110 |
111 |
112 | class FTPDataField(XByteField):
113 | """
114 | this is a field class for handling the ftp data
115 | @attention: this class inherets XByteField
116 | """
117 | holds_packets = 1
118 | name = "FtpDataField"
119 | myresult = ""
120 |
121 | def __init__(self, name, default):
122 | """
123 | FTPDataField constructor, for initializing instance variables
124 | @param name: name of the field
125 | @param default: Scapy has many formats to represent the data
126 | internal, human and machine. anyways you may sit this param to None.
127 | """
128 | self.name = name
129 | self.fmt = "!B"
130 | Field.__init__(self, name, default, "!B")
131 |
132 | def getfield(self, pkt, s):
133 | cstream = -1
134 | if pkt.underlayer.name == "TCP":
135 | cstream = dissector.check_stream(\
136 | pkt.underlayer.underlayer.fields["src"],\
137 | pkt.underlayer.underlayer.fields["dst"],\
138 | pkt.underlayer.fields["sport"],\
139 | pkt.underlayer.fields["dport"],\
140 | pkt.underlayer.fields["seq"], s)
141 | if not cstream == -1:
142 | s = cstream
143 | if pkt.underlayer.name == "TCP" and cstream == -1:
144 | return "", ""
145 | name = get_file()
146 | if not dissector.Dissector.default_download_folder_changed:
147 | cwd = os.getcwd() + "/downloaded/"
148 | try:
149 | os.mkdir("downloaded")
150 | except:
151 | None
152 | f = open(cwd + clean_file_name(name, cwd), "wb")
153 | else:
154 | f = open(dissector.Dissector.path +\
155 | clean_file_name(name, dissector.Dissector.path), "wb")
156 | f.write(s)
157 | f.close()
158 | self.myresult = ""
159 | firstb = struct.unpack(self.fmt, s[0])[0]
160 | self.myresult = ""
161 | for c in s:
162 | ustruct = struct.unpack(self.fmt, c)
163 | byte = base64.standard_b64encode(str(ustruct[0]))
164 | self.myresult = self.myresult + byte
165 | if not is_created_session(pkt.underlayer.underlayer.fields["src"],
166 | pkt.underlayer.underlayer.fields["dst"],
167 | pkt.underlayer.fields["sport"]):
168 | return self.myresult, ""
169 | return "", self.myresult
170 |
171 |
172 | class FTPResArgField(StrField):
173 | """
174 | class field to handle the ftp responses' arguments
175 | @attention: it inherets StrField which is imported from Scapy
176 | """
177 | holds_packets = 1
178 | name = "FTPResArgField"
179 |
180 | def getfield(self, pkt, s):
181 | """
182 | this method will get the packet, takes what does need to be
183 | taken and let the remaining go, so it returns two values.
184 | first value which belongs to this field and the second is
185 | the remaining which does need to be dissected with
186 | other "field classes".
187 | @param pkt: holds the whole packet
188 | @param s: holds only the remaining data which is not dissected yet.
189 | """
190 | value = ""
191 | if "Entering Passive Mode (" in s:
192 | value = []
193 | res = s.split("Entering Passive Mode (")
194 | res.remove(res[0])
195 | res = res[0].split(").")
196 | del(res[len(res)-1])
197 | res = res[0].split(",")
198 | IP = res[0] + "." + res[1] + "." + res[2] + "." + res[3]
199 | Port = str(int(res[4]) * 256 + int(res[5]))
200 | value.append(("Passive IP Address", IP))
201 | value.append(("Passive Port Number", Port))
202 | if(create_session(IP, pkt.underlayer.underlayer.fields["dst"],
203 | Port)):
204 | bind(Port)
205 | return "", value
206 | else:
207 | value = s
208 | return "", value
209 |
210 | def __init__(self, name, default, fmt, remain=0):
211 | """
212 | FTPResArgField constructor for initializing the instance variables
213 | @param name: name of the field
214 | @param default: Scapy has many formats to represent the data
215 | internal, human and machine. anyways you may sit this param to None.
216 | @param fmt: specifying the format, this has been set to "H"
217 | @param remain: this parameter specifies the size of the remaining
218 | data so make it 0 to handle all of the data.
219 | """
220 | self.name = name
221 | StrField.__init__(self, name, default, fmt, remain)
222 |
223 |
224 | class FTPResField(StrField):
225 | """
226 | class field to handle the ftp responses
227 | @attention: it inherets StrField which is imported from Scapy
228 | """
229 | holds_packets = 1
230 | name = "FTPReField"
231 |
232 | def get_code_msg(self, cn):
233 | """
234 | method which returns message for a ftp code number
235 | @param cn: code number
236 | """
237 | codes = {
238 | "110": "Restart marker reply",
239 | "120": "Service ready in nnn minutes",
240 | "125": "Data connection already open; transfer starting",
241 | "150": "File status okay; about to open data connection",
242 | "200": "Command okay",
243 | "202": "Command not implemented, superfluous at this site",
244 | "211": "System status, or system help reply",
245 | "212": "Directory status",
246 | "213": "File status",
247 | "214": "Help message",
248 | "215": "NAME system type",
249 | "220": "Service ready for new user",
250 | "221": "Service closing control connection",
251 | "225": "Data connection open; no transfer in progress",
252 | "226": "Closing data connection",
253 | "227": "Entering Passive Mode",
254 | "230": "User logged in proceed",
255 | "250": "Requested file action okay completed",
256 | "257": "PATHNAME created",
257 | "331": "User name okay need password",
258 | "332": "Need account for login",
259 | "350": "Requested file action pending further information",
260 | "421": "Service not available closing control connection",
261 | "425": "Can't open data connection",
262 | "426": "Connection closed; transfer aborted",
263 | "450": "Requested file action not taken",
264 | "451": "Requested action aborted: local error in processing",
265 | "452": "Requested action not taken. Insufficient storage space in system",
266 | "500": "Syntax error command unrecognized",
267 | "501": "Syntax error in parameters or arguments",
268 | "502": "Command not implemented",
269 | "503": "Bad sequence of commands",
270 | "504": "Command not implemented for that parameter",
271 | "530": "Not logged in",
272 | "532": "Need account for storing files",
273 | "550": "Requested action not taken: File unavailable",
274 | "551": "Requested action aborted: page type unknown",
275 | "552": "Requested file action aborted: Exceeded storage allocation",
276 | "553": "Requested action not taken: File name not allowed",
277 | }
278 | if cn in codes:
279 | return codes[cn]
280 | return ""
281 |
282 | def getfield(self, pkt, s):
283 | """
284 | this method will get the packet, takes what does need to be
285 | taken and let the remaining go, so it returns two values.
286 | first value which belongs to this field and the second is
287 | the remaining which does need to be dissected with
288 | other "field classes".
289 | @param pkt: holds the whole packet
290 | @param s: holds only the remaining data which is not dissected yet.
291 | """
292 | remain = ""
293 | value = ""
294 | ls = s.split()
295 | length = len(ls)
296 | if length > 1:
297 | value = self.get_code_msg(ls[0]) + " (" + ls[0] + ")"
298 | if length == 2:
299 | remain = ls[1]
300 | return remain, value
301 | else:
302 | i = 1
303 | remain = ""
304 | while i < length:
305 | if i != 1:
306 | remain = remain + " " + ls[i]
307 | elif i == 1:
308 | remain = remain + ls[i]
309 | i = i + 1
310 | return remain, value
311 | else:
312 | return "", self.get_code_msg(ls[0]) + " (" + ls[0] + ")"
313 |
314 | def __init__(self, name, default, fmt, remain=0):
315 | """
316 | class constructor for initializing the instance variables
317 | @param name: name of the field
318 | @param default: Scapy has many formats to represent the data
319 | internal, human and machine. anyways you may sit this param to None.
320 | @param fmt: specifying the format, this has been set to "H"
321 | @param remain: this parameter specifies the size of the remaining
322 | data so make it 0 to handle all of the data.
323 | """
324 | self.name = name
325 | StrField.__init__(self, name, default, fmt, remain)
326 |
327 |
328 | class FTPReqField(StrField):
329 | holds_packets = 1
330 | name = "FTPReqField"
331 |
332 | def getfield(self, pkt, s):
333 | """
334 | this method will get the packet, takes what does need to be
335 | taken and let the remaining go, so it returns two values.
336 | first value which belongs to this field and the second is
337 | the remaining which does need to be dissected with
338 | other "field classes".
339 | @param pkt: holds the whole packet
340 | @param s: holds only the remaining data which is not dissected yet.
341 | """
342 | remain = ""
343 | value = ""
344 | ls = s.split()
345 | if ls[0].lower() == "retr":
346 | c = 1
347 | file = ""
348 | while c < len(ls):
349 | file = file + ls[c]
350 | c = c + 1
351 | if len(file) > 0:
352 | add_file(file)
353 | length = len(ls)
354 | if length > 1:
355 | value = ls[0]
356 | if length == 2:
357 | remain = ls[1]
358 | return remain, value
359 | else:
360 | i = 1
361 | remain = ""
362 | while i < length:
363 | remain = remain + ls[i] + " "
364 | i = i + 1
365 | return remain, value
366 | else:
367 | return "", ls[0]
368 |
369 | def __init__(self, name, default, fmt, remain=0):
370 | """
371 | class constructor for initializing the instance variables
372 | @param name: name of the field
373 | @param default: Scapy has many formats to represent the data
374 | internal, human and machine. anyways you may sit this param to None.
375 | @param fmt: specifying the format, this has been set to "H"
376 | @param remain: this parameter specifies the size of the remaining
377 | data so make it 0 to handle all of the data.
378 | """
379 | self.name = name
380 | StrField.__init__(self, name, default, fmt, remain)
381 |
382 |
383 | class FTPData(Packet):
384 | """
385 | class for dissecting the ftp data
386 | @attention: it inherets Packet class from Scapy library
387 | """
388 | name = "ftp"
389 | fields_desc = [FTPDataField("data", "")]
390 |
391 |
392 | class FTPResponse(Packet):
393 | """
394 | class for dissecting the ftp responses
395 | @attention: it inherets Packet class from Scapy library
396 | """
397 | name = "ftp"
398 | fields_desc = [FTPResField("command", "", "H"),
399 | FTPResArgField("argument", "", "H")]
400 |
401 |
402 | class FTPRequest(Packet):
403 | """
404 | class for dissecting the ftp requests
405 | @attention: it inherets Packet class from Scapy library
406 | """
407 | name = "ftp"
408 | fields_desc = [FTPReqField("command", "", "H"),
409 | StrField("argument", "", "H")]
410 |
411 | bind_layers(TCP, FTPResponse, sport=21)
412 | bind_layers(TCP, FTPRequest, dport=21)
413 | bind_layers(TCP, FTPData, dport=20)
414 | bind_layers(TCP, FTPData, dport=20)
415 |
--------------------------------------------------------------------------------
/http.py:
--------------------------------------------------------------------------------
1 | import base64
2 | import os
3 | import string
4 | import random
5 | from scapy.packet import *
6 | from scapy.fields import *
7 | from scapy.ansmachine import *
8 | from scapy.layers.inet import *
9 | import dissector
10 |
11 |
12 | downloaded_files = []
13 |
14 |
15 | def name_generator(size=9, chars=string.ascii_uppercase + string.digits):
16 | """
17 | this method is for generating a randndom name for the downloaded files
18 | @param size: number of random characters
19 | @param chars: type of the random characters
20 | """
21 | return ''.join(random.choice(chars) for x in range(size))
22 |
23 |
24 | def clean_file_name(name, path):
25 | """
26 | this method is for cleaning the carved file name if it has some special chars
27 | which is not allowed in most of the operating systems or if the specified folder
28 | in path variable has another file has the same name.
29 | @param name: the carved file name
30 | @param path: the directory path
31 | """
32 | ls = list(name)
33 | result = ""
34 | length = len(ls)
35 | files = os.listdir(path)
36 | if len(name) > 25 or name in files or name == "NoName":
37 | return name_generator()
38 | i = 0
39 | while i < length:
40 | if ls[i].isalnum() or ls[i] == ".":
41 | result = result + ls[i]
42 | i = i + 1
43 | if len(result) > 0:
44 | return result
45 | else:
46 | return name_generator()
47 |
48 |
49 | def add_file(Src, Dst, SPort, DPort, name, seq):
50 | """
51 | this method is for storing the carved file name.
52 | @param Src: source ip address
53 | @param Dst: destination ip address
54 | @param SPort: source port number
55 | @param DPort: destination port number
56 | @param name: the carved file name
57 | @param seq: sequence number
58 | """
59 | downloaded_files.append((Src, Dst, SPort, DPort, name[1:], seq))
60 |
61 |
62 | def get_file(Src, Dst, SPort, DPort, ack):
63 | """
64 | this method is for retrieving the stored file name
65 | @param Src: source ip address
66 | @param Dst: destination ip address
67 | @param SPort: source port number
68 | @param DPort: destination port number
69 | @param ack: acknowledgment number
70 | """
71 | for element in downloaded_files:
72 | if Src == element[1] and Dst == element[0] and\
73 | SPort == element[3] and DPort == element[2] and\
74 | ack == element[5]:
75 | return element[4]
76 | return "NoName"
77 |
78 |
79 | class HTTPReqField(StrField):
80 | """
81 | field class for handling http requests
82 | @attention: it inherets StrField from Scapy library
83 | """
84 | holds_packets = 1
85 | name = "HTTPReqField"
86 |
87 | def getfield(self, pkt, s):
88 | """
89 | this method will get the packet, takes what does need to be
90 | taken and let the remaining go, so it returns two values.
91 | first value which belongs to this field and the second is
92 | the remaining which does need to be dissected with
93 | other "field classes".
94 | @param pkt: holds the whole packet
95 | @param s: holds only the remaining data which is not dissected yet.
96 | """
97 | cstream = -1
98 | if pkt.underlayer.name == "TCP":
99 | cstream = dissector.check_stream(\
100 | pkt.underlayer.underlayer.fields["src"],\
101 | pkt.underlayer.underlayer.fields["dst"],\
102 | pkt.underlayer.fields["sport"], pkt.underlayer.fields["dport"],\
103 | pkt.underlayer.fields["seq"], s)
104 | if not cstream == -1:
105 | s = cstream
106 | if pkt.underlayer.name == "TCP" and cstream == -1:
107 | return "", ""
108 | remain = ""
109 | value = ""
110 | if self.name == "request-line: ":
111 | ls = s.splitlines(True)
112 | f = ls[0].split()
113 | length = len(f)
114 | if length == 3:
115 | value = "Method:" + f[0] + ", Request-URI:" +\
116 | f[1] + ", HTTP-Version:" + f[2]
117 | HTTPMethodsRFC2616 = ['get','post','options','head','put','delete','trace','connect']
118 | #HTTP methods as per rfc2616 http://www.ietf.org/rfc/rfc2616
119 | #There are other methods in other RFCs but nobody cares about those.
120 | if f[0].lower() in HTTPMethodsRFC2616:
121 | add_file(pkt.underlayer.underlayer.fields["src"],\
122 | pkt.underlayer.underlayer.fields["dst"],\
123 | pkt.underlayer.fields["sport"],\
124 | pkt.underlayer.fields["dport"], f[1],\
125 | pkt.underlayer.fields["seq"] + len(s))
126 | ls.remove(ls[0])
127 | for element in ls:
128 | remain = remain + element
129 | return remain, value
130 | return s, ""
131 |
132 |
133 | class HTTPResField(StrField):
134 | """
135 | field class for handling http requests
136 | @attention: it inherets StrField from Scapy library
137 | """
138 | holds_packets = 1
139 | name = "HTTPResField"
140 | fin = False
141 |
142 | def get_code_msg(self, cn):
143 | """
144 | method returns the message for the http code number
145 | @param cn: code number
146 | """
147 | codes = {
148 | "100": "Continue",
149 | "101": "Switching Protocols",
150 | "102": "Processing",
151 | "199": "Informational - Others",
152 | "200": "OK",
153 | "201": "Created",
154 | "202": "Accepted",
155 | "203": "Non-Authoritative Information",
156 | "204": "No Content",
157 | "205": "Reset Content",
158 | "206": "Partial Content",
159 | "207": "Multi-Status",
160 | "299": "Success - Others",
161 | "300": "Multiple Choices",
162 | "301": "Moved Permanently",
163 | "302": "Moved Temporarily",
164 | "303": "See Other",
165 | "304": "Not Modified",
166 | "305": "Use Proxy",
167 | "306": "(Unused)",
168 | "307": "Temporary Redirect",
169 | "399": "Redirection - Others",
170 | "400": "Bad Request",
171 | "401": "Unauthorized",
172 | "402": "Payment Required",
173 | "403": "Forbidden",
174 | "404": "Not Found",
175 | "405": "Method Not Allowed",
176 | "406": "Not Acceptable",
177 | "407": "Proxy Authentication Required",
178 | "408": "Request Time-out",
179 | "409": "Conflict",
180 | "410": "Gone",
181 | "411": "Length Required",
182 | "412": "Precondition Failed",
183 | "413": "Request Entity Too Large",
184 | "414": "Request-URI Too Large",
185 | "415": "Unsupported Media Type",
186 | "416": "Requested Range Not Satisfiable",
187 | "417": "Expectation Failed",
188 | "422": "Unprocessable Entity",
189 | "423": "Locked",
190 | "424": "Failed Dependency",
191 | "499": "Client Error - Others",
192 | "500": "Internal Server Error",
193 | "501": "Not Implemented",
194 | "502": "Bad Gateway",
195 | "503": "Service Unavailable",
196 | "504": "Gateway Time-out",
197 | "505": "HTTP Version not supported",
198 | "599": "Server Error - Others"}
199 |
200 | if cn in codes:
201 | return codes[cn]
202 | return ""
203 |
204 | def getfield(self, pkt, s):
205 | """
206 | this method will get the packet, takes what does need to be
207 | taken and let the remaining go, so it returns two values.
208 | first value which belongs to this field and the second is
209 | the remaining which does need to be dissected with
210 | other "field classes".
211 | @param pkt: holds the whole packet
212 | @param s: holds only the remaining data which is not dissected yet.
213 | """
214 | seq = pkt.underlayer.fields["seq"]
215 | cstream = -1
216 | if pkt.underlayer.name == "TCP":
217 | cstream = dissector.check_stream(\
218 | pkt.underlayer.underlayer.fields["src"],\
219 | pkt.underlayer.underlayer.fields["dst"],\
220 | pkt.underlayer.fields["sport"],\
221 | pkt.underlayer.fields["dport"],\
222 | pkt.underlayer.fields["seq"], s)
223 | if not cstream == -1:
224 | s = cstream
225 | if pkt.underlayer.name == "TCP" and cstream == -1:
226 | return "", ""
227 | remain = ""
228 | value = ""
229 | if self.name == "status-line: " and s.startswith("HTTP/"):
230 | ls = s.splitlines(True)
231 | f = ls[0].split()
232 | length = len(f)
233 | if length == 3:
234 | value = "HTTP-Version:" + f[0] + ", Status-Code:" +\
235 | f[1] + ", Reason-Phrase:" + f[2]
236 | ls.remove(ls[0])
237 | for element in ls:
238 | remain = remain + element
239 | return remain, value
240 | return s, ""
241 |
242 |
243 | #class HTTPMsgField(XByteField):
244 | class HTTPMsgField(XByteField):
245 | """
246 | field class for handling http body
247 | @attention: it inherets XByteField from Scapy library
248 | """
249 | holds_packets = 1
250 | name = "HTTPMsgField"
251 | myresult = ""
252 |
253 | def __init__(self, name, default):
254 | """
255 | class constructor, for initializing instance variables
256 | @param name: name of the field
257 | @param default: Scapy has many formats to represent the data
258 | internal, human and machine. anyways you may sit this param to None.
259 | """
260 | self.name = name
261 | self.fmt = "!B"
262 | Field.__init__(self, name, default, "!B")
263 |
264 | def getfield(self, pkt, s):
265 | """
266 | this method will get the packet, takes what does need to be
267 | taken and let the remaining go, so it returns two values.
268 | first value which belongs to this field and the second is
269 | the remaining which does need to be dissected with
270 | other "field classes".
271 | @param pkt: holds the whole packet
272 | @param s: holds only the remaining data which is not dissected yet.
273 | """
274 | if s.startswith("\r\n"):
275 | s = s.lstrip("\r\n")
276 | if s == "":
277 | return "", ""
278 | name = get_file(pkt.underlayer.underlayer.fields["src"],\
279 | pkt.underlayer.underlayer.fields["dst"],\
280 | pkt.underlayer.fields["sport"],\
281 | pkt.underlayer.fields["dport"],\
282 | pkt.underlayer.fields["ack"])
283 | if pkt.underlayer.fields["sport"] == 80:
284 | if not dissector.Dissector.default_download_folder_changed:
285 | cwd = os.getcwd() + "/downloaded/"
286 | try:
287 | os.mkdir("downloaded")
288 | except:
289 | None
290 | f = open(cwd + clean_file_name(name, cwd), "wb")
291 | else:
292 | f = open(dissector.Dissector.path +\
293 | clean_file_name(name, dissector.Dissector.path), "wb")
294 | f.write(s)
295 | f.close()
296 | self.myresult = ""
297 | for c in s:
298 | self.myresult = self.myresult + base64.standard_b64encode(c)
299 |
300 | if self.myresult[-1:] == " ":
301 | self.myresult = self.myresult.rstrip()
302 | return "", self.myresult
303 |
304 |
305 | class HTTPField(StrField):
306 | """
307 | field class for handling http fields
308 | @attention: it inherets StrField from Scapy library
309 | """
310 | holds_packets = 1
311 | name = "HTTPField"
312 |
313 | def getfield(self, pkt, s):
314 | """
315 | this method will get the packet, takes what does need to be
316 | taken and let the remaining go, so it returns two values.
317 | first value which belongs to this field and the second is
318 | the remaining which does need to be dissected with
319 | other "field classes".
320 | @param pkt: holds the whole packet
321 | @param s: holds only the remaining data which is not dissected yet.
322 | """
323 | if self.name == "unknown-header(s): ":
324 | remain = ""
325 | value = []
326 | ls = s.splitlines(True)
327 | i = -1
328 | for element in ls:
329 | i = i + 1
330 | if element == "\r\n":
331 | return s, []
332 | elif element != "\r\n"\
333 | and (": " in element[:10])\
334 | and (element[-2:] == "\r\n"):
335 | value.append(element)
336 | ls.remove(ls[i])
337 | remain = ""
338 | unknown = True
339 | for element in ls:
340 | if element != "\r\n" and (": " in element[:15])\
341 | and (element[-2:] == "\r\n") and unknown:
342 | value.append(element)
343 | else:
344 | unknown = False
345 | remain = remain + element
346 | return remain, value
347 | return s, []
348 |
349 | remain = ""
350 | value = ""
351 | ls = s.splitlines(True)
352 | i = -1
353 | for element in ls:
354 | i = i + 1
355 | if element.upper().startswith(self.name.upper()):
356 | value = element
357 | value = value.strip(self.name)
358 | ls.remove(ls[i])
359 | remain = ""
360 | for element in ls:
361 | remain = remain + element
362 | return remain, value
363 | return s, ""
364 |
365 | def __init__(self, name, default, fmt, remain=0):
366 | """
367 | class constructor for initializing the instance variables
368 | @param name: name of the field
369 | @param default: Scapy has many formats to represent the data
370 | internal, human and machine. anyways you may sit this param to None.
371 | @param fmt: specifying the format, this has been set to "H"
372 | @param remain: this parameter specifies the size of the remaining
373 | data so make it 0 to handle all of the data.
374 | """
375 | self.name = name
376 | StrField.__init__(self, name, default, fmt, remain)
377 |
378 |
379 | class HTTPRequest(Packet):
380 | """
381 | class for handling http requests
382 | @attention: it inherets Packet from Scapy library
383 | """
384 | name = "http"
385 | fields_desc = [HTTPReqField("request-line: ", "", "H"),
386 | HTTPField("cache-control: ", "", "H"),
387 | HTTPField("connection: ", "", "H"),
388 | HTTPField("date: ", "", "H"),
389 | HTTPField("pragma: ", "", "H"),
390 | HTTPField("trailer: ", "", "H"),
391 | HTTPField("transfer-encoding: ", "", "H"),
392 | HTTPField("upgrade: ", "", "H"),
393 | HTTPField("dnt: ", "", "H"),
394 | HTTPField("x-requested-with: ", "", "H"),
395 | HTTPField("via: ", "", "H"),
396 | HTTPField("Warning: ", "", "H"),
397 | HTTPField("accept: ", "", "H"),
398 | HTTPField("accept-encoding: ", "", "H"),
399 | HTTPField("accept-language: ", "", "H"),
400 | HTTPField("content-length: ", "", "H"),
401 | HTTPField("accept-charset: ", "", "H"),
402 | HTTPField("expect: ", "", "H"),
403 | HTTPField("authorization: ", "", "H"),
404 | HTTPField("accept-datetime: ", "", "H"),
405 | HTTPField("from: ", "", "H"),
406 | HTTPField("host: ", "", "H"),
407 | HTTPField("if-match: ", "", "H"),
408 | HTTPField("if-modified-since: ", "", "H"),
409 | HTTPField("iIf-none-match: ", "", "H"),
410 | HTTPField("if-range: ", "", "H"),
411 | HTTPField("if-unmodified-since: ", "", "H"),
412 | HTTPField("max-forwards: ", "", "H"),
413 | HTTPField("proxy-authorization: ", "", "H"),
414 | HTTPField("range: ", "", "H"),
415 | HTTPField("referer: ", "", "H"),
416 | HTTPField("te: ", "", "H"),
417 | HTTPField("user-agent: ", "", "H"),
418 | HTTPField("link: ", "", "H"),
419 | HTTPField("mime-version: ", "", "H"),
420 | HTTPField("title: ", "", "H"),
421 | HTTPField("uri: ", "", "H"),
422 | HTTPField("cookie: ", "", "H"),
423 | HTTPField("set-cookie: ", "", "H"),
424 | HTTPField("x-forwarded-for: ", "", "H"),
425 | HTTPField("keep-alive: ", "", "H"),
426 | HTTPField("unknown-header(s): ", "", "H"),
427 | HTTPMsgField("message-body: ", "")]
428 |
429 |
430 | class HTTPResponse(Packet):
431 | """
432 | class for handling http responses
433 | @attention: it inherets Packet from Scapy library
434 | """
435 | name = "http"
436 | fields_desc = [HTTPResField("status-line: ", "", "H"),#responses123
437 | HTTPField("cache-control: ", "", "H"),
438 | HTTPField("connection: ", "", "H"),
439 | HTTPField("date: ", "", "H"),
440 | HTTPField("pragma: ", "", "H"),
441 | HTTPField("access-control-allow-origin: ", "", "H"),
442 | HTTPField("trailer: ", "", "H"),
443 | HTTPField("transfer-encoding: ", "", "H"),
444 | HTTPField("upgrade: ", "", "H"),
445 | HTTPField("via: ", "", "H"),
446 | HTTPField("warning: ", "", "H"),
447 | HTTPField("accept-ranges: ", "", "H"),
448 | HTTPField("age: ", "", "H"),
449 | HTTPField("etag: ", "", "H"),
450 | HTTPField("location: ", "", "H"),
451 | HTTPField("proxy-authenticate: ", "", "H"),
452 | HTTPField("retry-after: ", "", "H"),
453 | HTTPField("server: ", "", "H"),
454 | HTTPField("vary: ", "", "H"),
455 | HTTPField("allow: ", "", "H"),
456 | HTTPField("content-encoding: ", "", "H"),
457 | HTTPField("content-language: ", "", "H"),
458 | HTTPField("content-length: ", "", "H"),
459 | HTTPField("content-disposition: ", "", "H"),
460 | HTTPField("strict-transport-security: ", "", "H"),
461 | HTTPField("www-authenticate: ", "", "H"),
462 | HTTPField("x-frame-options: ", "", "H"),
463 | HTTPField("x-xss-protection: ", "", "H"),
464 | HTTPField("x-powered-by: ", "", "H"),
465 | HTTPField("content-security-policy: ", "", "H"),
466 | HTTPField("x-content-security-policy: ", "", "H"),
467 | HTTPField("x-webkit-csp: ", "", "H"),
468 | HTTPField("x-ua-compatible: ", "", "H"),
469 | HTTPField("x-content-type-options: ", "", "H"),
470 | HTTPField("x-ua-compatible: ", "", "H"),
471 | HTTPField("refresh: ", "", "H"),
472 | HTTPField("content-md5: ", "", "H"),
473 | HTTPField("content-range: ", "", "H"),
474 | HTTPField("content-type: ", "", "H"),
475 | HTTPField("expires: ", "", "H"),
476 | HTTPField("last-modified: ", "", "H"),
477 | HTTPField("extension-header: ", "", "H"),
478 | HTTPField("link: ", "", "H"),
479 | HTTPField("mime-version: ", "", "H"),
480 | HTTPField("retry-after: ", "", "H"),
481 | HTTPField("title: ", "", "H"),
482 | HTTPField("uri: ", "", "H"),
483 | HTTPField("public: ", "", "H"),
484 | HTTPField("accept-patch: ", "", "H"),
485 | HTTPField("cookie: ", "", "H"),
486 | HTTPField("set-cookie: ", "", "H"),
487 | #HTTPField("x-forwarded-for: ", "", "H"), X-Forwarded for is not a response header, it's a request
488 | HTTPField("keep-alive: ", "", "H"),
489 | HTTPField("unknown-header(s): ", "", "H"),
490 | HTTPMsgField("message-body: ", "")]
491 |
492 |
493 | bind_layers(TCP, HTTPResponse, sport=80)
494 | bind_layers(TCP, HTTPRequest, dport=80)
495 |
--------------------------------------------------------------------------------
/imap.py:
--------------------------------------------------------------------------------
1 | from scapy.packet import *
2 | from scapy.fields import *
3 | from scapy.ansmachine import *
4 | from scapy.layers.inet import *
5 | import dissector
6 |
7 |
8 | class IMAPField(StrField):
9 | """
10 | field class for handling imap packets
11 | @attention: it inherets StrField from Scapy library
12 | """
13 | holds_packets = 1
14 | name = "IMAPField"
15 |
16 | def getfield(self, pkt, s):
17 | """
18 | this method will get the packet, takes what does need to be
19 | taken and let the remaining go, so it returns two values.
20 | first value which belongs to this field and the second is
21 | the remaining which does need to be dissected with
22 | other "field classes".
23 | @param pkt: holds the whole packet
24 | @param s: holds only the remaining data which is not dissected yet.
25 | """
26 | cstream = -1
27 | if pkt.underlayer.name == "TCP":
28 | cstream = dissector.check_stream(\
29 | pkt.underlayer.underlayer.fields["src"],\
30 | pkt.underlayer.underlayer.fields["dst"],\
31 | pkt.underlayer.fields["sport"],\
32 | pkt.underlayer.fields["dport"],\
33 | pkt.underlayer.fields["seq"], s)
34 | if not cstream == -1:
35 | s = cstream
36 | remain = ""
37 | value = ""
38 | ls = s.splitlines()
39 | myresult = ""
40 | lslen = len(ls)
41 | i = 0
42 | k = 0
43 | for line in ls:
44 | k = k + 1
45 | ls2 = line.split()
46 | length = len(ls2)
47 | if length > 1:
48 | value = ls2[0]
49 | c = 1
50 | remain = ""
51 | while c < length:
52 | remain = remain + ls2[c] + " "
53 | c = c + 1
54 | if self.name.startswith("request"):
55 | myresult = myresult + "Request Tag: " +\
56 | value + ", Request Argument: " + remain
57 | if k < lslen:
58 | myresult = myresult + " | "
59 | if self.name.startswith("response"):
60 | myresult = myresult + "Response Tag: " +\
61 | value + ", Response Argument: " + remain
62 | if k < lslen:
63 | myresult = myresult + " | "
64 | i = i + 1
65 | if i == lslen:
66 | return "", myresult
67 |
68 | def __init__(self, name, default, fmt, remain=0):
69 | """
70 | class constructor for initializing the instance variables
71 | @param name: name of the field
72 | @param default: Scapy has many formats to represent the data
73 | internal, human and machine. anyways you may sit this param to None.
74 | @param fmt: specifying the format, this has been set to "H"
75 | @param remain: this parameter specifies the size of the remaining
76 | data so make it 0 to handle all of the data.
77 | """
78 | self.name = name
79 | StrField.__init__(self, name, default, fmt, remain)
80 |
81 |
82 | class IMAPRes(Packet):
83 | """
84 | class for handling imap responses
85 | @attention: it inherets Packet from Scapy library
86 | """
87 | name = "imap"
88 | fields_desc = [IMAPField("response", "", "H")]
89 |
90 |
91 | class IMAPReq(Packet):
92 | """
93 | class for handling imap requests
94 | @attention: it inherets Packet from Scapy library
95 | """
96 | name = "imap"
97 | fields_desc = [IMAPField("request", "", "H")]
98 |
99 |
100 | bind_layers(TCP, IMAPReq, dport=143)
101 | bind_layers(TCP, IMAPRes, sport=143)
102 |
--------------------------------------------------------------------------------
/irc.py:
--------------------------------------------------------------------------------
1 | from scapy.packet import *
2 | from scapy.fields import *
3 | from scapy.ansmachine import *
4 | from scapy.layers.inet import *
5 | import dissector
6 |
7 |
8 | class IRCResField(StrField):
9 | """
10 | field class for handling irc responses
11 | @attention: it inherets StrField from Scapy library
12 | """
13 | holds_packets = 1
14 | name = "IRCResField"
15 |
16 | def getfield(self, pkt, s):
17 | """
18 | this method will get the packet, takes what does need to be
19 | taken and let the remaining go, so it returns two values.
20 | first value which belongs to this field and the second is
21 | the remaining which does need to be dissected with
22 | other "field classes".
23 | @param pkt: holds the whole packet
24 | @param s: holds only the remaining data which is not dissected yet.
25 | """
26 | cstream = -1
27 | if pkt.underlayer.name == "TCP":
28 | cstream = dissector.check_stream(\
29 | pkt.underlayer.underlayer.fields["src"],\
30 | pkt.underlayer.underlayer.fields["dst"],\
31 | pkt.underlayer.fields["sport"],\
32 | pkt.underlayer.fields["dport"],\
33 | pkt.underlayer.fields["seq"], s)
34 | if not cstream == -1:
35 | s = cstream
36 | value = ""
37 | ls = s.split("\r\n")
38 | length = len(ls)
39 | if length == 1:
40 | return "", value
41 | elif length > 1:
42 | value = ""
43 | value = value + "response: " + ls[0]
44 | i = 1
45 | while i < length - 1:
46 | value = value + " response: " + ls[i]
47 | if i < length - 2:
48 | value = value + " | "
49 | i = i + 1
50 | return "", value
51 | else:
52 | return "", ""
53 |
54 | def __init__(self, name, default, fmt, remain=0):
55 | """
56 | class constructor for initializing the instance variables
57 | @param name: name of the field
58 | @param default: Scapy has many formats to represent the data
59 | internal, human and machine. anyways you may sit this param to None.
60 | @param fmt: specifying the format, this has been set to "H"
61 | @param remain: this parameter specifies the size of the remaining
62 | data so make it 0 to handle all of the data.
63 | """
64 | self.name = name
65 | StrField.__init__(self, name, default, fmt, remain)
66 |
67 |
68 | class IRCReqField(StrField):
69 | """
70 | field class for handling irc requests
71 | @attention: it inherets StrField from Scapy library
72 | """
73 | holds_packets = 1
74 | name = "IRCReqField"
75 |
76 | def getfield(self, pkt, s):
77 | """
78 | this method will get the packet, takes what does need to be
79 | taken and let the remaining go, so it returns two values.
80 | first value which belongs to this field and the second is
81 | the remaining which does need to be dissected with
82 | other "field classes".
83 | @param pkt: holds the whole packet
84 | @param s: holds only the remaining data which is not dissected yet.
85 | """
86 | cstream = -1
87 | if pkt.underlayer.name == "TCP":
88 | cstream = dissector.check_stream(\
89 | pkt.underlayer.underlayer.fields["src"],\
90 | pkt.underlayer.underlayer.fields["dst"],\
91 | pkt.underlayer.fields["sport"],\
92 | pkt.underlayer.fields["dport"],\
93 | pkt.underlayer.fields["seq"], s)
94 | if not cstream == -1:
95 | s = cstream
96 | remain = ""
97 | value = ""
98 | ls = s.split()
99 | length = len(ls)
100 | if length > 1:
101 | value = "command: " + ls[0] + ","
102 | if length == 2:
103 | remain = ls[1]
104 | value = value + " Parameters: " + remain
105 | return "", value
106 | else:
107 | i = 1
108 | remain = ""
109 | while i < length:
110 | if i != 1:
111 | remain = remain + " " + ls[i]
112 | else:
113 | remain = remain + ls[i]
114 | i = i + 1
115 | value = value + " Parameters: " + remain
116 | return "", value
117 | else:
118 | return "", ls[0]
119 |
120 | def __init__(self, name, default, fmt, remain=0):
121 | """
122 | class constructor for initializing the instance variables
123 | @param name: name of the field
124 | @param default: Scapy has many formats to represent the data
125 | internal, human and machine. anyways you may sit this param to None.
126 | @param fmt: specifying the format, this has been set to "H"
127 | @param remain: this parameter specifies the size of the remaining
128 | data so make it 0 to handle all of the data.
129 | """
130 | self.name = name
131 | StrField.__init__(self, name, default, fmt, remain)
132 |
133 |
134 | class IRCRes(Packet):
135 | """
136 | class for handling irc responses
137 | @attention: it inherets Packet from Scapy library
138 | """
139 | name = "irc"
140 | fields_desc = [IRCResField("response", "", "H")]
141 |
142 |
143 | class IRCReq(Packet):
144 | """
145 | class for handling irc requests
146 | @attention: it inherets Packet from Scapy library
147 | """
148 | name = "irc"
149 | fields_desc = [IRCReqField("command", "", "H")]
150 |
151 | bind_layers(TCP, IRCReq, dport=6660)
152 | bind_layers(TCP, IRCReq, dport=6661)
153 | bind_layers(TCP, IRCReq, dport=6662)
154 | bind_layers(TCP, IRCReq, dport=6663)
155 | bind_layers(TCP, IRCReq, dport=6664)
156 | bind_layers(TCP, IRCReq, dport=6665)
157 | bind_layers(TCP, IRCReq, dport=6666)
158 | bind_layers(TCP, IRCReq, dport=6667)
159 | bind_layers(TCP, IRCReq, dport=6668)
160 | bind_layers(TCP, IRCReq, dport=6669)
161 | bind_layers(TCP, IRCReq, dport=7000)
162 | bind_layers(TCP, IRCReq, dport=194)
163 | bind_layers(TCP, IRCReq, dport=6697)
164 |
165 |
166 | bind_layers(TCP, IRCRes, sport=6660)
167 | bind_layers(TCP, IRCRes, sport=6661)
168 | bind_layers(TCP, IRCRes, sport=6662)
169 | bind_layers(TCP, IRCRes, sport=6663)
170 | bind_layers(TCP, IRCRes, sport=6664)
171 | bind_layers(TCP, IRCRes, sport=6665)
172 | bind_layers(TCP, IRCRes, sport=6666)
173 | bind_layers(TCP, IRCRes, sport=6667)
174 | bind_layers(TCP, IRCRes, sport=6668)
175 | bind_layers(TCP, IRCRes, sport=6669)
176 | bind_layers(TCP, IRCRes, sport=7000)
177 | bind_layers(TCP, IRCRes, sport=194)
178 | bind_layers(TCP, IRCRes, sport=6697)
179 |
--------------------------------------------------------------------------------
/pop.py:
--------------------------------------------------------------------------------
1 | from scapy.packet import *
2 | from scapy.fields import *
3 | from scapy.ansmachine import *
4 | from scapy.layers.inet import *
5 | import dissector
6 |
7 |
8 | class POPField(StrField):
9 | """
10 | field class for handling pop requests
11 | @attention: it inherets StrField from Scapy library
12 | """
13 | holds_packets = 1
14 | name = "POPField"
15 |
16 | def getfield(self, pkt, s):
17 | """
18 | this method will get the packet, takes what does need to be
19 | taken and let the remaining go, so it returns two values.
20 | first value which belongs to this field and the second is
21 | the remaining which does need to be dissected with
22 | other "field classes".
23 | @param pkt: holds the whole packet
24 | @param s: holds only the remaining data which is not dissected yet.
25 | """
26 | cstream = -1
27 | if pkt.underlayer.name == "TCP":
28 | cstream = dissector.check_stream(\
29 | pkt.underlayer.underlayer.fields["src"],\
30 | pkt.underlayer.underlayer.fields["dst"],\
31 | pkt.underlayer.fields["sport"],\
32 | pkt.underlayer.fields["dport"],\
33 | pkt.underlayer.fields["seq"], s)
34 | if not cstream == -1:
35 | s = cstream
36 | remain = ""
37 | value = ""
38 | ls = s.splitlines()
39 | myresult = []
40 | lslen = len(ls)
41 | i = 0
42 | k = 0
43 | for line in ls:
44 | k = k + 1
45 | ls2 = line.split()
46 | length = len(ls2)
47 | if length > 1:
48 | value = ls2[0]
49 | c = 1
50 | remain = ""
51 | while c < length:
52 | remain = remain + ls2[c] + " "
53 | c = c + 1
54 | if self.name.startswith("request"):
55 | myresult = myresult + "Request Command: " + value +\
56 | ", Request Parameter(s): " + remain
57 | if k < lslen:
58 | myresult = myresult + " | "
59 | if self.name.startswith("response"):
60 | myresult = myresult + "Response Indicator: " + value +\
61 | ", Response Parameter(s): " + remain
62 | if k < lslen:
63 | myresult = myresult + " | "
64 | i = i + 1
65 | if i == lslen:
66 | return "", myresult
67 |
68 | def __init__(self, name, default, fmt, remain=0):
69 | """
70 | class constructor for initializing the instance variables
71 | @param name: name of the field
72 | @param default: Scapy has many formats to represent the data
73 | internal, human and machine. anyways you may sit this param to None.
74 | @param fmt: specifying the format, this has been set to "H"
75 | @param remain: this parameter specifies the size of the remaining
76 | data so make it 0 to handle all of the data.
77 | """
78 | self.name = name
79 | StrField.__init__(self, name, default, fmt, remain)
80 |
81 |
82 | class POPRes(Packet):
83 | """
84 | class for handling pop responses
85 | @attention: it inherets Packet from Scapy library
86 | """
87 | name = "pop"
88 | fields_desc = [POPField("response", "", "H")]
89 |
90 |
91 | class POPReq(Packet):
92 | """
93 | class for handling pop requests
94 | @attention: it inherets Packet from Scapy library
95 | """
96 | name = "pop"
97 | fields_desc = [POPField("request", "", "H")]
98 |
99 |
100 | bind_layers(TCP, POPReq, dport=110)
101 | bind_layers(TCP, POPRes, sport=110)
102 |
--------------------------------------------------------------------------------
/sip.py:
--------------------------------------------------------------------------------
1 | import base64
2 | from scapy.packet import *
3 | from scapy.fields import *
4 | from scapy.ansmachine import *
5 | from scapy.layers.inet import *
6 | from scapy.layers.dns import *
7 | import dissector
8 |
9 |
10 | class SIPStartField(StrField):
11 | """
12 | field class for handling sip start field
13 | @attention: it inherets StrField from Scapy library
14 | """
15 | holds_packets = 1
16 | name = "SIPStartField"
17 |
18 | def getfield(self, pkt, s):
19 | """
20 | this method will get the packet, takes what does need to be
21 | taken and let the remaining go, so it returns two values.
22 | first value which belongs to this field and the second is
23 | the remaining which does need to be dissected with
24 | other "field classes".
25 | @param pkt: holds the whole packet
26 | @param s: holds only the remaining data which is not dissected yet.
27 | """
28 | cstream = -1
29 | if pkt.underlayer.name == "TCP":
30 | cstream = dissector.check_stream(\
31 | pkt.underlayer.underlayer.fields["src"],\
32 | pkt.underlayer.underlayer.fields["dst"],\
33 | pkt.underlayer.fields["sport"],\
34 | pkt.underlayer.fields["dport"],\
35 | pkt.underlayer.fields["seq"], s)
36 | if not cstream == -1:
37 | s = cstream
38 | remain = ""
39 | value = ""
40 | ls = s.splitlines(True)
41 | f = ls[0].split()
42 | if "SIP" in f[0]:
43 | ls = s.splitlines(True)
44 | f = ls[0].split()
45 | length = len(f)
46 | value = ""
47 | if length == 3:
48 | value = "SIP-Version:" + f[0] + ", Status-Code:" +\
49 | f[1] + ", Reason-Phrase:" + f[2]
50 | ls.remove(ls[0])
51 | for element in ls:
52 | remain = remain + element
53 | else:
54 | value = ls[0]
55 | ls.remove(ls[0])
56 | for element in ls:
57 | remain = remain + element
58 | return remain, value
59 | elif "SIP" in f[2]:
60 | ls = s.splitlines(True)
61 | f = ls[0].split()
62 | length = len(f)
63 | value = []
64 | if length == 3:
65 | value = "Method:" + f[0] + ", Request-URI:" +\
66 | f[1] + ", SIP-Version:" + f[2]
67 | ls.remove(ls[0])
68 | for element in ls:
69 | remain = remain + element
70 | else:
71 | value = ls[0]
72 | ls.remove(ls[0])
73 | for element in ls:
74 | remain = remain + element
75 | return remain, value
76 | else:
77 | return s, ""
78 |
79 |
80 | class SIPMsgField(StrField):
81 | """
82 | field class for handling the body of sip packets
83 | @attention: it inherets StrField from Scapy library
84 | """
85 | holds_packets = 1
86 | name = "SIPMsgField"
87 | myresult = ""
88 |
89 | def __init__(self, name, default):
90 | """
91 | class constructor, for initializing instance variables
92 | @param name: name of the field
93 | @param default: Scapy has many formats to represent the data
94 | internal, human and machine. anyways you may sit this param to None.
95 | """
96 | self.name = name
97 | self.fmt = "!B"
98 | Field.__init__(self, name, default, "!B")
99 |
100 | def getfield(self, pkt, s):
101 | """
102 | this method will get the packet, takes what does need to be
103 | taken and let the remaining go, so it returns two values.
104 | first value which belongs to this field and the second is
105 | the remaining which does need to be dissected with
106 | other "field classes".
107 | @param pkt: holds the whole packet
108 | @param s: holds only the remaining data which is not dissected yet.
109 | """
110 | if s.startswith("\r\n"):
111 | s = s.lstrip("\r\n")
112 | if s == "":
113 | return "", ""
114 | self.myresult = ""
115 | for c in s:
116 | self.myresult = self.myresult + base64.standard_b64encode(c)
117 | return "", self.myresult
118 |
119 |
120 | class SIPField(StrField):
121 | """
122 | field class for handling the body of sip fields
123 | @attention: it inherets StrField from Scapy library
124 | """
125 | holds_packets = 1
126 | name = "SIPField"
127 |
128 | def getfield(self, pkt, s):
129 | """
130 | this method will get the packet, takes what does need to be
131 | taken and let the remaining go, so it returns two values.
132 | first value which belongs to this field and the second is
133 | the remaining which does need to be dissected with
134 | other "field classes".
135 | @param pkt: holds the whole packet
136 | @param s: holds only the remaining data which is not dissected yet.
137 | """
138 | if self.name == "unknown-header(s): ":
139 | remain = ""
140 | value = []
141 | ls = s.splitlines(True)
142 | i = -1
143 | for element in ls:
144 | i = i + 1
145 | if element == "\r\n":
146 | return s, []
147 | elif element != "\r\n" and (": " in element[:10])\
148 | and (element[-2:] == "\r\n"):
149 | value.append(element)
150 | ls.remove(ls[i])
151 | remain = ""
152 | unknown = True
153 | for element in ls:
154 | if element != "\r\n" and (": " in element[:15])\
155 | and (element[-2:] == "\r\n") and unknown:
156 | value.append(element)
157 | else:
158 | unknow = False
159 | remain = remain + element
160 | return remain, value
161 | return s, []
162 |
163 | remain = ""
164 | value = ""
165 | ls = s.splitlines(True)
166 | i = -1
167 | for element in ls:
168 | i = i + 1
169 | if element.upper().startswith(self.name.upper()):
170 | value = element
171 | value = value.strip(self.name)
172 | ls.remove(ls[i])
173 | remain = ""
174 | for element in ls:
175 | remain = remain + element
176 | return remain, value[len(self.name) + 1:]
177 | return s, ""
178 |
179 | def __init__(self, name, default, fmt, remain=0):
180 | """
181 | class constructor for initializing the instance variables
182 | @param name: name of the field
183 | @param default: Scapy has many formats to represent the data
184 | internal, human and machine. anyways you may sit this param to None.
185 | @param fmt: specifying the format, this has been set to "H"
186 | @param remain: this parameter specifies the size of the remaining
187 | data so make it 0 to handle all of the data.
188 | """
189 | self.name = name
190 | StrField.__init__(self, name, default, fmt, remain)
191 |
192 |
193 | class SIP(Packet):
194 | """
195 | class for handling the body of sip packets
196 | @attention: it inherets Packet from Scapy library
197 | """
198 | name = "sip"
199 | fields_desc = [SIPStartField("start-line: ", "", "H"),
200 | SIPField("accept: ", "", "H"),
201 | SIPField("accept-contact: ", "", "H"),
202 | SIPField("accept-encoding: ", "", "H"),
203 | SIPField("accept-language: ", "", "H"),
204 | SIPField("accept-resource-priority: ", "", "H"),
205 | SIPField("alert-info: ", "", "H"),
206 | SIPField("allow: ", "", "H"),
207 | SIPField("allow-events: ", "", "H"),
208 | SIPField("authentication-info: ", "", "H"),
209 | SIPField("authorization: ", "", "H"),
210 | SIPField("call-id: ", "", "H"),
211 | SIPField("call-info: ", "", "H"),
212 | SIPField("contact: ", "", "H"),
213 | SIPField("content-disposition: ", "", "H"),
214 | SIPField("content-encoding: ", "", "H"),
215 | SIPField("content-language: ", "", "H"),
216 | SIPField("content-length: ", "", "H"),
217 | SIPField("content-type: ", "", "H"),
218 | SIPField("cseq: ", "", "H"),
219 | SIPField("date: ", "", "H"),
220 | SIPField("error-info: ", "", "H"),
221 | SIPField("event: ", "", "H"),
222 | SIPField("expires: ", "", "H"),
223 | SIPField("from: ", "", "H"),
224 | SIPField("in-reply-to: ", "", "H"),
225 | SIPField("join: ", "", "H"),
226 | SIPField("max-forwards: ", "", "H"),
227 | SIPField("mime-version: ", "", "H"),
228 | SIPField("min-expires: ", "", "H"),
229 | SIPField("min-se: ", "", "H"),
230 | SIPField("organization: ", "", "H"),
231 | SIPField("p-access-network-info: ", "", "H"),
232 | SIPField("p-asserted-identity: ", "", "H"),
233 | SIPField("p-associated-uri: ", "", "H"),
234 | SIPField("p-called-party-id: ", "", "H"),
235 | SIPField("p-charging-function-addresses: ", "", "H"),
236 | SIPField("p-charging-vector: ", "", "H"),
237 | SIPField("p-dcs-trace-party-id: ", "", "H"),
238 | SIPField("p-dcs-osps: ", "", "H"),
239 | SIPField("p-dcs-billing-info: ", "", "H"),
240 | SIPField("p-dcs-laes: ", "", "H"),
241 | SIPField("p-dcs-redirect: ", "", "H"),
242 | SIPField("p-media-authorization: ", "", "H"),
243 | SIPField("p-preferred-identity: ", "", "H"),
244 | SIPField("p-visited-network-id: ", "", "H"),
245 | SIPField("path: ", "", "H"),
246 | SIPField("priority: ", "", "H"),
247 | SIPField("privacy: ", "", "H"),
248 | SIPField("proxy-authenticate: ", "", "H"),
249 | SIPField("proxy-authorization: ", "", "H"),
250 | SIPField("proxy-require: ", "", "H"),
251 | SIPField("rack: ", "", "H"),
252 | SIPField("reason: ", "", "H"),
253 | SIPField("record-route: ", "", "H"),
254 | SIPField("referred-by: ", "", "H"),
255 | SIPField("reject-contact: ", "", "H"),
256 | SIPField("replaces: ", "", "H"),
257 | SIPField("reply-to: ", "", "H"),
258 | SIPField("request-disposition: ", "", "H"),
259 | SIPField("require: ", "", "H"),
260 | SIPField("resource-priority: ", "", "H"),
261 | SIPField("retry-after: ", "", "H"),
262 | SIPField("route: ", "", "H"),
263 | SIPField("rseq: ", "", "H"),
264 | SIPField("security-client: ", "", "H"),
265 | SIPField("security-server: ", "", "H"),
266 | SIPField("security-verify: ", "", "H"),
267 | SIPField("server: ", "", "H"),
268 | SIPField("service-route: ", "", "H"),
269 | SIPField("session-expires: ", "", "H"),
270 | SIPField("sip-etag: ", "", "H"),
271 | SIPField("sip-if-match: ", "", "H"),
272 | SIPField("subject: ", "", "H"),
273 | SIPField("subscription-state: ", "", "H"),
274 | SIPField("supported: ", "", "H"),
275 | SIPField("timestamp: ", "", "H"),
276 | SIPField("to: ", "", "H"),
277 | SIPField("unsupported: ", "", "H"),
278 | SIPField("user-agent: ", "", "H"),
279 | SIPField("via: ", "", "H"),
280 | SIPField("warning: ", "", "H"),
281 | SIPField("www-authenticate: ", "", "H"),
282 | SIPField("refer-to: ", "", "H"),
283 | SIPField("history-info: ", "", "H"),
284 | SIPField("unknown-header(s): ", "", "H"),
285 | SIPMsgField("message-body: ", "")]
286 |
287 | bind_layers(TCP, SIP, sport=5060)
288 | bind_layers(TCP, SIP, dport=5060)
289 | bind_layers(UDP, SIP, sport=5060)
290 | bind_layers(UDP, SIP, dport=5060)
291 |
--------------------------------------------------------------------------------
/smtp.py:
--------------------------------------------------------------------------------
1 | import base64
2 | import base64
3 | import os
4 | import string
5 | import random
6 | from scapy.packet import *
7 | from scapy.fields import *
8 | from scapy.ansmachine import *
9 | from scapy.layers.inet import *
10 | import dissector
11 |
12 |
13 | def name_generator(size=9, chars=string.ascii_uppercase + string.digits):
14 | """
15 | this method is for generating a randndom name for the downloaded files
16 | @param size: number of random characters
17 | @param chars: type of the random characters
18 | """
19 | return ''.join(random.choice(chars) for x in range(size))
20 |
21 |
22 | src = ""
23 | dst = ""
24 | sport = ""
25 | dport = ""
26 | seq = ""
27 |
28 | # holds smtp sessions
29 | bounded = []
30 |
31 |
32 | def get_tcp_ip():
33 | """
34 | this method is for retrieving the ip and tcp values
35 | """
36 | return src, dst, sport, dport, seq
37 |
38 |
39 | def set_tcp_ip(srcp, dstp, sportp, dportp, seqp):
40 | """
41 | this method is for set values in the global variables for tcp/ip
42 | @param srcp: source ip address
43 | @param dstp: destination ip address
44 | @param sportp: source port number
45 | @param dPortp: destination port number
46 | @param seqp: sequence number
47 | """
48 | global src, dst, sport, dport, seq
49 | src = srcp
50 | dst = dstp
51 | sport = sportp
52 | dport = dportp
53 | seq = seqp
54 |
55 |
56 | def bind(Src, Dst, Port):
57 | """
58 | method for creating smtp data sessions
59 | @param Src: source ip address
60 | @param Dst: destination ip address
61 | @param Port: source port number
62 | """
63 | bounded.append([Src, Dst, Port])
64 |
65 |
66 | def unbind(Src, Dst, Port):
67 | """
68 | do the opposite of bind()
69 | """
70 | if [Src, Dst, Port] in bounded:
71 | bounded.remove([Src, Dst, Port])
72 |
73 |
74 | def is_bounded(Src, Dst, Port):
75 | """
76 | returns true if the session is already bounded
77 | @param Src: source ip address
78 | @param Dst: destination ip address
79 | @param Port: source port number
80 | """
81 | if [Src, Dst, Port] in bounded:
82 | return True
83 | return False
84 |
85 |
86 | class SMTPDataField(XByteField):
87 | """
88 | this is a field class for handling the smtp data
89 | @attention: this class inherets XByteField
90 | """
91 | holds_packets = 1
92 | name = "SMTPDataField"
93 | myresult = ""
94 |
95 | def __init__(self, name, default):
96 | """
97 | class constructor, for initializing instance variables
98 | @param name: name of the field
99 | @param default: Scapy has many formats to represent the data
100 | internal, human and machine. anyways you may sit this param to None.
101 | """
102 | self.name = name
103 | self.fmt = "!B"
104 | Field.__init__(self, name, default, "!B")
105 |
106 | def getfield(self, pkt, s):
107 | """
108 | this method will get the packet, takes what does need to be
109 | taken and let the remaining go, so it returns two values.
110 | first value which belongs to this field and the second is
111 | the remaining which does need to be dissected with
112 | other "field classes".
113 | @param pkt: holds the whole packet
114 | @param s: holds only the remaining data which is not dissected yet.
115 | """
116 |
117 | src, dst, sport, dport, seq = get_tcp_ip()
118 |
119 | cstream = -1
120 | cstream = dissector.check_stream(src, dst, sport, dport, seq, s)
121 | if not cstream == -1:
122 | s = cstream
123 | if cstream == -1:
124 | return "", ""
125 |
126 | name = name_generator()
127 | if not dissector.Dissector.default_download_folder_changed:
128 | cwd = os.getcwd() + "/downloaded/"
129 | try:
130 | os.mkdir("downloaded")
131 | except:
132 | None
133 | f = open(cwd + name, "wb")
134 | else:
135 | f = open(dissector.Dissector.path + name, "wb")
136 | f.write(s)
137 | f.close()
138 | self.myresult = ""
139 | for c in s:
140 | self.myresult = self.myresult + base64.standard_b64encode(c)
141 | return "", self.myresult
142 |
143 |
144 | class SMTPResField(StrField):
145 | """
146 | this is a field class for handling the smtp data
147 | @attention: this class inherets StrField
148 | """
149 | holds_packets = 1
150 | name = "SMTPReField"
151 |
152 | def get_code_msg(self, cn):
153 | """
154 | method returns a message for every a specific code number
155 | @param cn: code number
156 | """
157 | codes = {
158 | "500": "Syntax error, command unrecognized",
159 | "501": "Syntax error in parameters or arguments",
160 | "502": "Command not implemented",
161 | "503": "Bad sequence of commands",
162 | "504": "Command parameter not implemented",
163 | "211": "System status, or system help reply",
164 | "214": "Help message",
165 | "220": " Service ready",
166 | "221": " Service closing transmission channel",
167 | "421": " Service not available,\
168 | closing transmission channel",
169 | "250": "Requested mail action okay, completed",
170 | "251": "User not local; will forward to ",
171 | "450": "Requested mail action not taken: mailbox unavailable",
172 | "550": "Requested action not taken: mailbox unavailable",
173 | "451": "Requested action aborted: error in processing",
174 | "551": "User not local; please try ",
175 | "452": "Requested action not taken: insufficient system\
176 | storage",
177 | "552": "Requested mail action aborted: exceeded storage\
178 | allocation",
179 | "553": "Requested action not taken: mailbox name not allowed",
180 | "354": "Start mail input; end with .",
181 | "554": "Transaction failed",
182 | "211": "System status, or system help reply",
183 | "214": "Help message",
184 | "220": " Service ready",
185 | "221": " Service closing transmission channel",
186 | "250": "Requested mail action okay, completed",
187 | "251": "User not local; will forward to ",
188 | "354": "Start mail input; end with .",
189 | "421": " Service not available, closing \
190 | transmission channel",
191 | "450": "Requested mail action not taken: mailbox unavailable",
192 | "451": "Requested action aborted: local error in processing",
193 | "452": "Requested action not taken: insufficient system\
194 | storage",
195 | "500": "Syntax error, command unrecognized",
196 | "501": "Syntax error in parameters or arguments",
197 | "502": "Command not implemented",
198 | "503": "Bad sequence of commands",
199 | "504": "Command parameter not implemented",
200 | "550": "Requested action not taken: mailbox unavailable",
201 | "551": "User not local; please try ",
202 | "552": "Requested mail action aborted: exceeded storage\
203 | allocation",
204 | "553": "Requested action not taken: mailbox name not allowed",
205 | "554": "Transaction failed"}
206 | if cn in codes:
207 | return codes[cn]
208 | return "Unknown Response Code"
209 |
210 | def getfield(self, pkt, s):
211 | """
212 | this method will get the packet, takes what does need to be
213 | taken and let the remaining go, so it returns two values.
214 | first value which belongs to this field and the second is
215 | the remaining which does need to be dissected with
216 | other "field classes".
217 | @param pkt: holds the whole packet
218 | @param s: holds only the remaining data which is not dissected yet.
219 | """
220 | cstream = -1
221 | if pkt.underlayer.name == "TCP":
222 | cstream = dissector.check_stream(\
223 | pkt.underlayer.underlayer.fields["src"],\
224 | pkt.underlayer.underlayer.fields["dst"],\
225 | pkt.underlayer.fields["sport"],\
226 | pkt.underlayer.fields["dport"],\
227 | pkt.underlayer.fields["seq"], s)
228 | if not cstream == -1:
229 | s = cstream
230 | remain = ""
231 | value = ""
232 | ls = s.splitlines()
233 | length = len(ls)
234 | if length == 1:
235 | value = ls[0]
236 | arguments = ""
237 | first = True
238 | res = value.split(" ")
239 | for arg in res:
240 | if not first:
241 | arguments = arguments + arg + " "
242 | first = False
243 | if "-" in res[0]:
244 | value = "(" + res[0][:3] + ") " +\
245 | self.get_code_msg(res[0][:3]) + " " + res[0][3:]
246 | else:
247 | value = "(" + res[0] + ") " + self.get_code_msg(res[0])
248 | return arguments[:-1], [value]
249 |
250 | if length > 1:
251 | reponses = []
252 | for element in ls:
253 | element = element.split(" ")
254 | arguments = ""
255 | first = True
256 | for arg in element:
257 | if not first:
258 | arguments = arguments + arg + " "
259 | first = False
260 | if "-" in element[0]:
261 | reponses.append(["(" + element[0][:3] + ") " +
262 | self.get_code_msg(element[0][:3]) +
263 | " " + element[0][3:], arguments[:-1]])
264 | else:
265 | reponses.append(["(" + element[0] + ") " +
266 | self.get_code_msg(element[0][:-1]),
267 | arguments])
268 | return "", reponses
269 | return "", ""
270 |
271 | def __init__(self, name, default, fmt, remain=0):
272 | """
273 | class constructor for initializing the instance variables
274 | @param name: name of the field
275 | @param default: Scapy has many formats to represent the data
276 | internal, human and machine. anyways you may sit this param to None.
277 | @param fmt: specifying the format, this has been set to "H"
278 | @param remain: this parameter specifies the size of the remaining
279 | data so make it 0 to handle all of the data.
280 | """
281 | self.name = name
282 | StrField.__init__(self, name, default, fmt, remain)
283 |
284 |
285 | class SMTPReqField(StrField):
286 | holds_packets = 1
287 | name = "SMTPReqField"
288 |
289 | def getfield(self, pkt, s):
290 | """
291 | this method will get the packet, takes what does need to be
292 | taken and let the remaining go, so it returns two values.
293 | first value which belongs to this field and the second is
294 | the remaining which does need to be dissected with
295 | other "field classes".
296 | @param pkt: holds the whole packet
297 | @param s: holds only the remaining data which is not dissected yet.
298 | """
299 | cstream = -1
300 | if pkt.underlayer.name == "TCP":
301 | cstream = dissector.check_stream(\
302 | pkt.underlayer.underlayer.fields["src"],\
303 | pkt.underlayer.underlayer.fields["dst"],\
304 | pkt.underlayer.fields["sport"],\
305 | pkt.underlayer.fields["dport"],\
306 | pkt.underlayer.fields["seq"], s)
307 | if not cstream == -1:
308 | s = cstream
309 | remain = ""
310 | value = ""
311 | ls = s.split()
312 | length = len(ls)
313 | if ls[0].upper() == "DATA":
314 | bind(pkt.underlayer.underlayer.fields["src"],
315 | pkt.underlayer.underlayer.fields["dst"],
316 | pkt.underlayer.fields["sport"])
317 | return "", "DATA"
318 | if ls[0].upper() == "QUIT":
319 | unbind(pkt.underlayer.underlayer.fields["src"],
320 | pkt.underlayer.underlayer.fields["dst"],
321 | pkt.underlayer.fields["sport"])
322 | return "", "QUIT"
323 | if is_bounded(pkt.underlayer.underlayer.fields["src"],
324 | pkt.underlayer.underlayer.fields["dst"],
325 | pkt.underlayer.fields["sport"]):
326 | set_tcp_ip(pkt.underlayer.underlayer.fields["src"],
327 | pkt.underlayer.underlayer.fields["dst"],
328 | pkt.underlayer.fields["sport"],\
329 | pkt.underlayer.fields["dport"],\
330 | pkt.underlayer.fields["seq"])
331 | smtpd = SMTPData(s).fields["data"]
332 | return "", ["DATA", smtpd]
333 |
334 | if length > 1:
335 | value = ls[0]
336 | if length == 2:
337 | remain = ls[1]
338 | return remain, value
339 | else:
340 | i = 1
341 | remain = ' '
342 | while i < length:
343 | remain = remain + ls[i] + ' '
344 | i = i + 1
345 | return remain[:-1], value
346 | else:
347 | return "", ls[0]
348 |
349 | def __init__(self, name, default, fmt, remain=0):
350 | """
351 | class constructor for initializing the instance variables
352 | @param name: name of the field
353 | @param default: Scapy has many formats to represent the data
354 | internal, human and machine. anyways you may sit this param to None.
355 | @param fmt: specifying the format, this has been set to "H"
356 | @param remain: this parameter specifies the size of the remaining
357 | data so make it 0 to handle all of the data.
358 | """
359 | self.name = name
360 | StrField.__init__(self, name, default, fmt, remain)
361 |
362 |
363 | class SMTPData(Packet):
364 | """
365 | class for handling the smtp data
366 | @attention: this class inherets Packet
367 | """
368 |
369 | name = "smtp"
370 | fields_desc = [SMTPDataField("data", "")]
371 |
372 |
373 | class SMTPResponse(Packet):
374 | """
375 | class for handling the smtp responses
376 | @attention: this class inherets Packet
377 | """
378 | name = "smtp"
379 | fields_desc = [SMTPResField("response", "", "H"),
380 | StrField("argument", "", "H")]
381 |
382 |
383 | class SMTPRequest(Packet):
384 | """
385 | class for handling the smtp requests
386 | @attention: this class inherets Packet
387 | """
388 | name = "smtp"
389 | fields_desc = [SMTPReqField("command", '', "H"),
390 | StrField("argument", '', "H")]
391 |
392 | bind_layers(TCP, SMTPResponse, sport=25)
393 | bind_layers(TCP, SMTPRequest, dport=25)
394 | bind_layers(TCP, SMTPResponse, sport=587)
395 | bind_layers(TCP, SMTPRequest, dport=587)
396 |
--------------------------------------------------------------------------------
/telnet.py:
--------------------------------------------------------------------------------
1 | import base64
2 | from scapy.packet import *
3 | from scapy.utils import *
4 | from scapy.fields import *
5 | from scapy.ansmachine import *
6 | from scapy.layers.inet import *
7 | import dissector
8 |
9 |
10 | class TELNETField(XByteField):
11 | """
12 | field class for handling the telnet packets
13 | @attention: this class inherets XByteField
14 | """
15 | holds_packets = 1
16 | name = "TELNETField"
17 | myresult = ""
18 |
19 | def __init__(self, name, default):
20 | """
21 | class constructor, for initializing instance variables
22 | @param name: name of the field
23 | @param default: Scapy has many formats to represent the data
24 | internal, human and machine. anyways you may sit this param to None.
25 | """
26 | self.name = name
27 | self.fmt = "!B"
28 | Field.__init__(self, name, default, "!B")
29 |
30 | def get_code_msg(self, cn):
31 | """
32 | method returns a message for every a specific code number
33 | @param cn: code number
34 | """
35 | codes = {0: "TRANSMIT-BINARY", 1: "ECHO",
36 | 3: "SUPPRESS-GO-AHEAD",
37 | 5: "STATUS", 6: "TIMING-MARK",
38 | 7: "RCTE", 10: "NAOCRD",
39 | 11: "NAOHTS", 12: "NAOHTD",
40 | 13: "NAOFFD", 14: "NAOVTS",
41 | 15: "NAOVTD", 16: "NAOLFD",
42 | 17: "EXTEND-ASCII",
43 | 18: "LOGOUT", 19: "BM", 20: "DET", 21: "SUPDUP",
44 | 22: "SUPDUP-OUTPUT", 23: "SEND-LOCATION",
45 | 24: "TERMINAL-TYPE", 25: "END-OF-RECORD",
46 | 26: "TUID", 27: "OUTMRK", 28: "TTYLOC", 29: "3270-REGIME",
47 | 30: "X.3-PAD", 31: "NAWS", 32: "TERMINAL-SPEED",
48 | 33: "TOGGLE-FLOW-CONTROL", 34: "LINEMODE",
49 | 35: "X-DISPLAY-LOCATION",
50 | 36: "ENVIRON", 37: "AUTHENTICATION", 38: "ENCRYPT",
51 | 39: "NEW-ENVIRON", 40: "TN3270E", 44: "COM-PORT-OPTION",
52 | 236: "End of Record", 237: "Suspend Current Process",
53 | 238: "Abort Process", 239: "End of File", 240: "SE",
54 | 241: "NOP", 242: "Data Mark", 243: "Break",
55 | 244: "Interrupt Process", 245: "Abort output",
56 | 246: "Are You There", 247: "Erase character",
57 | 248: "Erase Line", 249: "Go ahead", 250: "SB", 251: "WILL",
58 | 252: "WON'T", 253: "DO", 254: "DON'T", 255: "Command"}
59 | if cn in codes:
60 | return codes[cn] + " "
61 | return "UnknownCode[" + str(cn) + "] "
62 |
63 | def getfield(self, pkt, s):
64 | """
65 | this method will get the packet, takes what does need to be
66 | taken and let the remaining go, so it returns two values.
67 | first value which belongs to this field and the second is
68 | the remaining which does need to be dissected with
69 | other "field classes".
70 | @param pkt: holds the whole packet
71 | @param s: holds only the remaining data which is not dissected yet.
72 | """
73 | cstream = -1
74 | if pkt.underlayer.name == "TCP":
75 | cstream = dissector.check_stream(\
76 | pkt.underlayer.underlayer.fields["src"],\
77 | pkt.underlayer.underlayer.fields["dst"],\
78 | pkt.underlayer.fields["sport"],\
79 | pkt.underlayer.fields["dport"],\
80 | pkt.underlayer.fields["seq"], s)
81 | if not cstream == -1:
82 | s = cstream
83 | self.myresult = ""
84 | subOptions = False
85 | resultlist = []
86 | firstb = struct.unpack(self.fmt, s[0])[0]
87 | if firstb != 255:
88 | self.myresult = ""
89 | for c in s:
90 | self.myresult = self.myresult + base64.standard_b64encode(c)
91 | return "", "data " + self.myresult
92 |
93 | for c in s:
94 | ustruct = struct.unpack(self.fmt, c)
95 | command = self.get_code_msg(ustruct[0])
96 | if command == "SB ":
97 | subOptions = True
98 | self.myresult = self.myresult + "SB "
99 | continue
100 | if command == "SE ":
101 | subOptions = False
102 | self.myresult = self.myresult = self.myresult + "SE "
103 | continue
104 | if subOptions:
105 | self.myresult = self.myresult +\
106 | "subop(" + str(ustruct[0]) + ") "
107 | continue
108 | else:
109 | self.myresult = self.myresult + command
110 | comlist = self.myresult.split("Command ")
111 | for element in comlist:
112 | if element != "":
113 | resultlist.append(("command", element))
114 | #return "", resultlist
115 | return "", self.myresult
116 |
117 |
118 | class TELNET(Packet):
119 | """
120 | field class for handling the telnet packets
121 | @attention: this class inherets Packet
122 | """
123 | name = "telnet"
124 | fields_desc = [TELNETField("telnetpayload", "")]
125 |
126 | bind_layers(TCP, TELNET, dport=23)
127 | bind_layers(TCP, TELNET, sport=23)
128 | """
129 | pkts = rdpcap("/root/Desktop/telnet-cooked.pcap")
130 | for pkt in pkts:
131 | pkt.show()
132 | """
133 |
--------------------------------------------------------------------------------
/usedissector.py:
--------------------------------------------------------------------------------
1 | import json
2 |
3 | from dissector import *
4 |
5 | """
6 | this file is a test unit for a pcap library (mainly dissector.py
7 | and its associated protocols classes). This library uses and
8 | depends on Scapy library.
9 | """
10 | # instance of dissector class
11 | dissector = Dissector()
12 |
13 | #dissector.change_dfolder("/root/Desktop/aaa")
14 |
15 | # sending the pcap file to be dissected
16 | pkts = dissector.dissect_pkts("/root/Desktop/ssh.cap")
17 |
18 | print(pkts)
19 |
20 | f = open("/root/Desktop/ssh.txt", "w")
21 | print(pkts["ssh"])
22 | f.write(json.dumps(pkts, indent=4))
--------------------------------------------------------------------------------