├── 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)) --------------------------------------------------------------------------------