piwi/0000700000000000000000000000000010154737622011761 5ustar rootroot00000000000000piwi/Docs/0000700000000000000000000000000010154737620012647 5ustar rootroot00000000000000piwi/Docs/Gentoo/0000700000000000000000000000000010154737620014102 5ustar rootroot00000000000000piwi/Docs/Gentoo/prelude-nids-cvs-0.8.ebuild0000600000000000000000000000332607734055650020773 0ustar rootroot00000000000000inherit eutils ECVS_SERVER="cvs.prelude-ids.org:/cvsroot/prelude" ECVS_MODULE="prelude-nids" ECVS_BRANCH="${ECVS_MODULE}-`echo ${PV} | sed s:\\\.:-:g`" ECVS_TOP_DIR="${DISTDIR}/cvs-src/${ECVS_MODULE}" inherit cvs S=${WORKDIR}/${ECVS_MODULE} DESCRIPTION="Prelude-IDS Network Intrusion Detection System" HOMEPAGE="http://www.prelude-ids.org" LICENSE="GPL-2" SLOT="0" KEYWORDS="~x86" IUSE="doc" DEPEND="virtual/glibc dev-libs/libprelude-cvs !app-admin/prelude-nids !dev-libs/libprelude doc? ( dev-util/gtk-doc )" RDEPEND="${DEPEND}" src_compile() { local myconf export WANT_AUTOCONF_2_5="1" export WANT_AUTOMAKE_1_6="1" export MAKEOPTS="" # Doesn't compile if you using make -j use doc && myconf="${myconf} --enable-gtk-doc" || myconf="${myconf} --enable-gtk-doc=no" aclocal -I /usr/share/aclocal autoconf autoheader libtoolize -c --force --ltdl --automake automake --gnu -a -c cd libltdl mv configure.in configure.in.tmp echo "AC_PREREQ(2.50)" > configure.in cat configure.in.tmp >> configure.in rm -f configure.in.tmp aclocal -I /usr/share/aclocal autoconf autoheader libtoolize -c --force --ltdl --automake automake --gnu -a -c cd .. econf ${myconf} || die "econf failed" emake || die "emake failed" } src_install() { make DESTDIR=${D} install || die "make install failed" # We skip start/stop scripts with the -cvs verison # If you want the scripts then use non -cvs #insinto /etc/init.d #insopts -m 755 #newins ${FILESDIR}/gentoo.init prelude-nids #insinto /etc/conf.d #insopts -m 644 #newins ${FILESDIR}/gentoo.conf prelude-nids into /usr/share/prelude/ruleset mv ${D}/etc/prelude-nids/ruleset ${D}/usr/share/prelude/ruleset/nids dosym /usr/share/prelude/ruleset/nids /etc/prelude-nids/ruleset } piwi/Docs/Gentoo/prelude-manager-cvs-0.8.ebuild0000600000000000000000000000346007734055650021447 0ustar rootroot00000000000000inherit eutils ECVS_SERVER="cvs.prelude-ids.org:/cvsroot/prelude" ECVS_MODULE="prelude-manager" ECVS_BRANCH="${ECVS_MODULE}-`echo ${PV} | sed s:\\\.:-:g`" ECVS_TOP_DIR="${DISTDIR}/cvs-src/${ECVS_MODULE}" inherit cvs S=${WORKDIR}/${ECVS_MODULE} DESCRIPTION="Prelude-IDS Manager" HOMEPAGE="http://www.prelude-ids.org" LICENSE="GPL-2" SLOT="0" KEYWORDS="~x86" IUSE="ssl doc mysql postgres" DEPEND="virtual/glibc dev-libs/libprelude-cvs ssl? ( dev-libs/openssl ) doc? ( dev-util/gtk-doc ) mysql? ( dev-db/mysql ) postgres? ( dev-db/postgresql )" RDEPEND="${DEPEND}" src_compile() { local myconf export WANT_AUTOCONF_2_5="1" export WANT_AUTOMAKE_1_6="1" use ssl && myconf="${myconf} --enable-openssl" || myconf="${myconf} --enable-openssl=no" use doc && myconf="${myconf} --enable-gtk-doc" || myconf="${myconf} --enable-gtk-doc=no" use mysql && myconf="${myconf} --enable-mysql" || myconf="${myconf} --enable-mysql=no" use postgres && myconf="${myconf} --enable-postgresql" || myconf="${myconf} --enable-postgresql=no" aclocal -I /usr/share/aclocal autoconf autoheader libtoolize -c --force --ltdl --automake automake --gnu -a -c cd libltdl mv configure.in configure.in.tmp echo "AC_PREREQ(2.50)" > configure.in cat configure.in.tmp >> configure.in rm -f configure.in.tmp aclocal -I /usr/share/aclocal autoconf autoheader libtoolize -c --force --ltdl --automake automake --gnu -a -c cd .. econf ${myconf} || die "econf failed" emake || die "emake failed" } src_install() { make DESTDIR=${D} install || die "make install failed" # We skip start/stop scripts with the -cvs verison # If you want the scripts then use non -cvs #insinto /etc/init.d #insopts -m 755 #newins ${FILESDIR}/gentoo.init prelude-manager #insinto /etc/conf.d #insopts -m 644 #newins ${FILESDIR}/gentoo.conf prelude-manager } piwi/Docs/Gentoo/piwi-cvs-0.8.ebuild0000600000000000000000000000464707734055650017357 0ustar rootroot00000000000000inherit eutils ECVS_SERVER="cvs.prelude-ids.org:/cvsroot/prelude" ECVS_MODULE="piwi" ECVS_BRANCH="HEAD" ECVS_TOP_DIR="${DISTDIR}/cvs-src/${ECVS_MODULE}" inherit cvs S=${WORKDIR}/${ECVS_MODULE} DESCRIPTION="Prelude-IDS perl GUI" HOMEPAGE="http://www.prelude-ids.org" LICENSE="GPL-2" SLOT="0" KEYWORDS="~x86" IUSE="mysql postgres gd" DEPEND=" dev-lang/perl dev-perl/DBI dev-perl/Date-Calc postgresql? ( dev-perl/DBD-Pg ) mysql? ( dev-perl/DBD-mysql ) !net-analyzer/piwi gd? ( dev-perl/GDGraph dev-perl/Geo-IP ) " RDEPEND="${DEPEND}" src_install() { into /home/httpd/htdocs/piwi || die into /etc/piwi || die # "install" the files into the destination cp -aR ${S}/* ${D}/home/httpd/htdocs/piwi/ || die # Remove CVS directories : find ${D}/home/httpd/htdocs/piwi/ -name "CVS" | xargs rm -fR # Fix permissions # Opt not to use the ebuild functions fowners() and fperms() # as they doesn't seem to work recursively. chown -R root:apache ${D}/home/httpd/htdocs/piwi/* || die chown -R apache:apache ${D}/home/httpd/htdocs/piwi/generated || die chmod -R o-rwx ${D}/home/httpd/htdocs/piwi/* || die # Move files around and create symlinks to make sure configuration files # are not being overwritten when you do upgrades... mv ${D}/home/httpd/htdocs/piwi/generated/Filters ${D}/etc/piwi/Filters || die dosym /etc/piwi/Filters /home/httpd/htdocs/piwi/generated/Filters mv ${D}/home/httpd/htdocs/piwi/Profiles ${D}/etc/piwi/Profiles || die dosym /etc/piwi/Profiles /home/httpd/htdocs/piwi/Profiles mv ${D}/home/httpd/htdocs/piwi/Functions/config.pl ${D}/etc/piwi/config.pl || die dosym /etc/piwi/config.pl /home/httpd/htdocs/piwi/Functions/config.pl # Install configuration file for apache dodoc ${FILESDIR}/piwi-apache.conf } pkg_postinst() { einfo "" einfo "To have Apache run PIWI, please do the following:" einfo "1) Include the /usr/share/doc/${P}/piwi-apache.conf in your apache configuration" einfo "2) Edit /etc/conf.d/apache or /etc/conf.d/apache2 and add \"-D PIWI\"" einfo "3) Edit /etc/piwi/config.pl to reflect your settings" ewarn "" ewarn "NOTE: If you do not perform these steps PIWI will _not_ work." ewarn " You have been warned. Any bugs against this will be either:" ewarn "" ewarn " - directed to /dev/null" ewarn " - resolved with a RTFM comment" ewarn "" ewarn "Consider yourself warned" # Make sure that the user pay attention echo -ne "\a"; sleep 0,25 ; echo -ne "\a"; sleep 0,25 } piwi/Docs/Gentoo/libprelude-cvs-0.8.ebuild0000600000000000000000000000237607734055650020533 0ustar rootroot00000000000000inherit eutils ECVS_SERVER="cvs.prelude-ids.org:/cvsroot/prelude" ECVS_MODULE="libprelude" ECVS_BRANCH="${ECVS_MODULE}-`echo ${PV} | sed s:\\\.:-:g`" ECVS_TOP_DIR="${DISTDIR}/cvs-src/${ECVS_MODULE}" inherit cvs S=${WORKDIR}/${ECVS_MODULE} DESCRIPTION="Prelude-IDS Framework Library" HOMEPAGE="http://www.prelude-ids.org" LICENSE="GPL-2" SLOT="0" KEYWORDS="~x86" IUSE="ssl doc" DEPEND="virtual/glibc ssl? ( dev-libs/openssl ) doc? ( dev-util/gtk-doc )" RDEPEND="${DEPEND}" src_compile() { local myconf export WANT_AUTOCONF_2_5="1" export WANT_AUTOMAKE_1_6="1" use ssl && myconf="${myconf} --enable-openssl" || myconf="${myconf} --disable-openssl" use doc && myconf="${myconf} --enable-gtk-doc" || myconf="${myconf} --disable-gtk-doc" aclocal -I /usr/share/aclocal autoconf autoheader libtoolize -c --force --ltdl --automake automake --gnu -a -c cd libltdl mv configure.in configure.in.tmp echo "AC_PREREQ(2.50)" > configure.in cat configure.in.tmp >> configure.in rm -f configure.in.tmp aclocal -I /usr/share/aclocal autoconf autoheader libtoolize -c --force --ltdl --automake automake --gnu -a -c cd .. econf ${myconf} || die "econf failed" emake || die "emake failed" } src_install() { make DESTDIR=${D} install || die "make install failed" } piwi/Docs/Gentoo/prelude-lml-cvs-0.8.ebuild0000600000000000000000000000332307734055650020617 0ustar rootroot00000000000000inherit eutils ECVS_SERVER="cvs.prelude-ids.org:/cvsroot/prelude" ECVS_MODULE="prelude-lml" ECVS_BRANCH="${ECVS_MODULE}-`echo ${PV} | sed s:\\\.:-:g`" ECVS_TOP_DIR="${DISTDIR}/cvs-src/${ECVS_MODULE}" inherit cvs S=${WORKDIR}/${ECVS_MODULE} DESCRIPTION="Prelude-IDS Log Monitoring Lackey" HOMEPAGE="http://www.prelude-ids.org" LICENSE="GPL-2" SLOT="0" KEYWORDS="~x86" IUSE="doc" DEPEND="virtual/glibc dev-libs/libprelude-cvs !app-admin/prelude-lml !dev-libs/libprelude dev-libs/libpcre doc? ( dev-util/gtk-doc )" RDEPEND="${DEPEND}" src_compile() { local myconf export WANT_AUTOCONF_2_5="1" export WANT_AUTOMAKE_1_6="1" export MAKEOPTS="" # Doesn't compile if you using make -j use doc && myconf="${myconf} --enable-gtk-doc" || myconf="${myconf} --enable-gtk-doc=no" aclocal -I /usr/share/aclocal autoconf autoheader libtoolize -c --force --ltdl --automake automake --gnu -a -c cd libltdl mv configure.in configure.in.tmp echo "AC_PREREQ(2.50)" > configure.in cat configure.in.tmp >> configure.in rm -f configure.in.tmp aclocal -I /usr/share/aclocal autoconf autoheader libtoolize -c --force --ltdl --automake automake --gnu -a -c cd .. econf ${myconf} || die "econf failed" emake || die "emake failed" } src_install() { make DESTDIR=${D} install || die "make install failed" # We skip start/stop scripts with the -cvs verison # If you want the scripts then use non -cvs #insinto /etc/init.d #insopts -m 755 #newins ${FILESDIR}/gentoo.init prelude-lml #insinto /etc/conf.d #insopts -m 644 #newins ${FILESDIR}/gentoo.conf prelude-lml into /usr/share/prelude/ruleset mv ${D}/etc/prelude-lml/ruleset ${D}/usr/share/prelude/ruleset/lml dosym /usr/share/prelude/ruleset/lml /etc/prelude-lml/ruleset } piwi/Docs/CREDITS.txt0000600000000000000000000000401307742056561014514 0ustar rootroot00000000000000Stephane LOEUILLET (LeRoutier) : http://www.leroutier.net/Projects/ Main coder / Maintainer --------------------------------------------------------------------------- Laurent OUDOT : http://www.rstack.org/oudot/ feature requests and ideas (like nessus report correlation) code for Passive OS Fingerprint and Ethernet card 's Vendor lookup --------------------------------------------------------------------------- Yoann VANDOORSELAERE : http://alph.dyndns.org:8080/ bug hunting, ideas (HeartBeat page, Attacker score) Prelude IDS project founder/maintainer --------------------------------------------------------------------------- Krzysztof ZARASKA : http://mops.uci.agh.edu.pl/~kzaraska/ DB optimisation ideas Some testing (FreeBSD 4.7, Apache 2.x) --------------------------------------------------------------------------- Davor OCELIC (docelic) : http://linuks.mine.nu/~docelic/ Code clean-up to avoid numerous warnings --------------------------------------------------------------------------- Michael VERGOZ (descript) : http://www.sysdoor.[org|net|com]/ PHP Front-End (2nd one) Bug reports --------------------------------------------------------------------------- John GREEN (girona) : some testing (mod_perl and gd install) Provided me a PostgreSQL aware account Bug reports Doc on how to add functionnality to piwi : http://www.giggled.org.uk/piwi_custom.html --------------------------------------------------------------------------- Olaf GELLERT : http://www.pre-secure.de/ Alert external processing code --------------------------------------------------------------------------- Orlin DAMYANOV : http://www.grandlink.fr/ (GrandLink Network) New graphical theme and JS code for checkboxes --------------------------------------------------------------------------- Sebastien TRICAUD (toady) : debian required packages list --------------------------------------------------------------------------- (rolphin) : http://rolphin.grosgay.com/ PostScript work (for more professional graphical reports) piwi/Docs/TODO.txt0000600000000000000000000001045410003102373014143 0ustar rootroot00000000000000Following items are available only in piwi-0-9 branch : - use of libpreludeDB instead of direct DB access to make DB changes easiest Features : - Attacker details : via command-line tools or perl modules (nmap, whois, ...) - Top attacks for TCP, UDP, ICMP (level 4) by Port/Type - User profiles with rights management / auth : (started) . each user has its own filters . many more to come (if you have some ideas ...) - daily/monthly/whatever statistics (number and distribution of attacks) => Daniel Polombo (from ML, 10/2002) started - In AlertDetails, make every http and mail link clickable => Vincent Glaume (prelude IRC chan) - LML ruleset editor, beeing able to build a .rules file from scratch (me) - service discovery with on the fly filter creation via NMAP (me) Coding : - better checking of user inputs to improve security and avoid code injection - better/cleaner code that would also work under Apache::Registry (cgi and Apache::PerlRun only for now) - cache name resolutions to speed things a bit (girona's idea) - better documentation. with a FAQ as questions arrive. switch to another fmt ============================================================================ Alert Annotation : first off, there would be a need of supporting analyst-given scored.. or catagorization a simple 10 catagory where analysts can file the alerts is needed to start with.. oh, alert score, not the existing attacker score crap the catagories are: root/admin account compromise, user account compromise, attempted account compromise, misusage of service, attempted missusage of service, denial of service, poor security ot policy violation, reconnaissance, virus activity and finally No Action (ie: false positive, or access authorized) LeRoutier: well, it is a attacker scoring. i'll come to that ;) anyway, based on previous analyst-catagorization of alerts we can determen if the particular IP/net is hostile just relying on raw data is not enuff, becuase then our office would be the main attacker to our servers as we login to them, mostly as root.. so there is a need to verify and classify the raw alerts for what they really accomplished mboman: depends on your NIDS policy : catch everything including crap (attacks on products you don't own like IIS when you have apache) or catch only attacks related to services/ports/applications runnings this is especially important when you don't delete alerts (we never delete any alerts for tracking purposes) you surelly have a big fat prelude DB so well, in the end I want to have all rules enabled, even if the IIS attacks against Apache, as it is compromise efforts - not very good ones but still.. it is the 'ip is up to no good' rating ;) true, you really need a way to mark alerts as false positive if you use the catch all policy a IIS unicode exploit against apache, or a patched IIS is still a attempted account compromise.. attempted as it failed, but still the attack is really real.. which increases the 'ip is up to no good' score togeather with Nessus data you can (and we will) have a system that automaticly "removes" the attacks that are not working, a'la IIS against Apache when I say "remove" i mean that the analysts will never see the attacks, but the score is increasing.. also, based on previous catagorisations it can learn how things are handled.. like with robots.txt access.. after a while the system should learn what access you are ignoring (ie: search engines) and what is treated as reconnence. il faut que tu utilise le champ additional data, avec un champ "meaning" que tu reconnaisse apres dans le champ, tu update a chaque commentaire genre comme le BTS : Posted by : commentaire ============================================================================ HeartBeat : - detection automatique du Delta ah, envlever le 3600s codé en dr que tu dois avoir la possibilit? de configurer le delta dans la config, mais que par defaut, toi tu detecte ============================================================================ piwi/Docs/BUGS.txt0000600000000000000000000000065007616342663014163 0ustar rootroot00000000000000 - some caching problems with mod_perl, even under Apache::PerlRun. if you experience those, please stick to mod_cgi for now. (some code cleanup would fix it) => should now work under Apache::PerlRun but still problems under Apache::Registry (mod_perl expert needed) - fine tune (aka debug) the AlertDetails XML view which renders badly when objets are present several times (See AdditionalData for example) piwi/Docs/flt_file_format.txt0000600000000000000000000000265210002124426016535 0ustar rootroot00000000000000This short doc presents the filter file format for the perl web front-end : the name of the filter is the name of the file, minus its extension (.flt) so slashes '/' are forbidden (to avoid wild directory browsing) here is a sample flt file : comment=test with multicriteria filter : address S 81.96.66 && Class.name C ICMP desc=1 by_page=30 Formula=A AND B A=Address|address|S|81.91.66 B=Classification|name|C|ICMP as you see, there are several field types : (no specific order) - comment (mandatory) : one line comment about what this filter does - desc (mandatory) : if 1, reverse display order (Last -> First). other = 0 - by_page (mandatory) : number of results per page - Formula (mandatory) : contains boolean operations between criterias allowed elements : AND/OR/NOT, brakets, criteria names (A -> Z) - Criteria (1 at least) : letter (A-Z in uppercase) : identify the criteria in the formula value : (fields separated by a pipe (|) Table name : case sensitive Field name : case sensitive (even if all fields are lower-case) Operator : (case sensitive) = : equals to != : differs from > : is greater than < : is lower than >= : is greater or equal <= : is lower or equal S : starts with C : contains E : ends with M : matches (% as wild-card) Value : case insensitive piwi/Docs/LICENCE.txt0000600000000000000000000004330207616060233014454 0ustar rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. piwi/Docs/INSTALL-gentoo.txt0000600000000000000000000000164710007224377016016 0ustar rootroot00000000000000type the following : for the current official version : ACCEPT_KEYWORDS="~x86" emerge piwi then follow what is written at the end of installation this include adding this to apache configuration : (/etc/apache2/conf/apache2.conf) Options ExecCGI FollowSymLinks AllowOverride All DirectoryIndex index.pl PerlModule Apache::DBI SetHandler perl-script PerlHandler Apache::PerlRun PerlSendHeader On AddHandler cgi-script .pl and in "/etc/conf.d/apache2" add "-D PIWI" to APACHE2_OPTS string ========================== This version needs the following : app-text/ghostscript if you want to use the PS back-end dev-perl/CGI mandatory PDF::API2 (perl module) if you want to publish PDF reports (unfortunatly, no in portage for now) piwi/Docs/process_file_format.txt0000600000000000000000000000227710002544102017426 0ustar rootroot00000000000000.proc file format: those contain process-definitions for programms executed on selected alerts For each process that can be executed one of these files has to exist ----------------------------------------------------------------------- location : generated/Processing/ subdirectory ----------------------------------------------------------------------- file name : ProcessName+dot+proc (as "Save to tmp-file.proc") ----------------------------------------------------------------------- content: empty lines and lines starting with a # are considered comments and are ignored each line should be like this : parameter=value known parameters are (for now) : - Comment : Some comment about what this process is for - Command : the command that is actually executed, for example a line "Command=/bin/cat >>/tmp/logalerts" - AllowedUsers : The names of the users (as defined in the user profiles of the frontend) that are allowed to execute this process. The names are seperated by spaces. - OutputSeparator : optionnal, default value is $SPACE $LF : unix end of line (\n) $CRLF : windows end of line (\r\n) $SPACE : a single space $TAB : a single tab (\t) any char or string piwi/Docs/user_file_format.txt0000600000000000000000000000352410003240227016724 0ustar rootroot00000000000000.user file format : those file contain user-profiles. You must have one such file for each user accessing the front-end. example : users 'admin' and 'yoann' are in your .htpasswd file => create for them 'Profiles/admin.user' and 'Profiles/yoann.user' or they would only be able to be 'guest' ----------------------------------------------------------------------- location : Profiles/ sub-directory ----------------------------------------------------------------------- file name : UserName+dot+user (as guest.user for user guest) ----------------------------------------------------------------------- content : empty lines and lines starting with a # are considered comments and are ignored each line should be like this : parameter=value known parameters are (for now) : - FullName : user full name (not used for now) - IPAccess : IP mask to allow access by IP - priv_delete : could this user delete alerts (none|all) - priv_user : could this user change other users rights (not used for now) IPAccess could be : - an exact IP : 81.91.66.90 - an IP mask, 255 being wildcard : 81.91.255.255 User password is not stored in this file as we relly on web-server built-in auth (directory pass-protected by YOU). You just need an HTTP-AUTH compliant web-server (Basic or Digest). for example, for apache, you'll have : - a .htaccess file in the front-end main directory - a .htpasswd (Basic) or .htdigest (Digest) file somewhere Tutorials on how to make such files are available there : http://httpd.apache.org/docs/howto/htaccess.html (.htaccess files how-to) http://httpd.apache.org/docs/mod/mod_auth.html (Basic Auth) http://httpd.apache.org/docs/mod/mod_digest.html (Digest Auth) http://online.securityfocus.com/infocus/1368 (PartI) http://online.securityfocus.com/infocus/1369 (Part II) http://online.securityfocus.com/infocus/1370 (Part III) piwi/Docs/README.txt0000600000000000000000000000113007620060671014341 0ustar rootroot00000000000000Name : Prelude-IDS Perl Web Front-End Abstract : Providing a complete web front-end for the Prelude-Intrusion Detection System with features like : - Alert listing, sorting, masking - Alert details - Source centric view - Alert-type centric view - Source informations (IP, MAC, OS via NMAP, known open services) Team : See CREDITS.txt file for a complete and up-to-date list Installation : See INSTALL.txt file for complete instructions and requirement list Licence : G.P.L. v2 (see LICENCE.txt) Contact : mailto:piwi@LeRoutier.net http://www.leroutier.net/Projects/PreludeIDS/ piwi/Docs/CHANGES.txt0000600000000000000000000004256710010515472014466 0ustar rootroot000000000000002004-02-05 : long time since last "ChangeLog" update but lots of things changed - GD back-end is now deprecated (but still present). use PS (ghostscript) now for better graphs - HeartBeat parameters are now configurable in the config file - CGI.pm is used instead of old cgi-lib.pl - General code/style clean-up everywhere - PDF report generation (via command line, not from piwi web interface) - TimeZone is now auto-detected if not set in the config file - many more thing i have forgotten and i am too lazy to gather from CVS commits 2003-12-19 : - create piwi-0-8 branch for current stable release (HEAD for libpreludedb based piwi) 2003-12-05 : - Classes/BaseObject/Criteria/Filter.pm : - Filters.pl : fix a bug that added CreateTime to a custom filter new property for a Criteria, could be temporary (never stored in .flt) fixed some code indentation 2003-12-03 : - Classes/Statistics.pm : display_png() now returns 0 on error keep Statistic->Label() when creating PS based image - Functions/ps.pl : postscript() now returns 0 on error, 1 on success - Stats.pl : only require GD perl module if GD back-end is chosen - generated/Filters/invalid filter.flt : removed as it was filling error log with useless SQL errors 2003-10-21 : (Functions/Filtered_Links.pl) - Classification.* and Impact.* are facultative so avoid a warning when they are not present 2003-10-21 : (Functions/_AlertDetails.pl) - Cut ASCII PayLoad dump better (and avoid cutting
in the half) 2003-10-19 : (Templates/piechart.ps, Functions/ps.pl) - Remove a second definition of the 'comment' postscript function which was unsused - Fix a bug on histograms in stats : value draw on bar where not on the right Y value (plain value instead of percent) 2003-10-16 : (Templates/AlertList_Filters) - to select a radio HTML element, we have to use 'checked', not 'selected' : found by James Horvat 2003-10-15 : (Classes/Statistic.pm, Templates/*.ps, Functions/ps.pl, TopAttackers.pl, Templates/TopAttackers_Filters) - implemented vbar histogram PS back-end, on by default in Stats - 'Source only' by default in TopAttackers.pl 2003-10-12 : (Stats.pl, Classes/Statistic.pm) - Start cleaning graph generation - implemented pie-chart PS back-end, on by default 2003-10-11 : (TopAttack*s.pl, Templates/TopAttack*s*, prelude-ids.ps) - replace Templates/TopAttack*s.ps files by a single piechart.ps - move prelude-ids.ps common PS to Templates/ directory 2003-10-09 : (TopAttack*s.pl, Templates/TopAttack*s*, Functions/ps.pl) - Finish PS back-end for TopAttacks - Rewrite TopAttackers, separating data extraction from display - We now have 3 back-end (HTML, PS, GD) for TopAttacks and TopAttackers for know, changing back-end by hand, using ?backend=HTML or =PS or =GD 2003-09-25 : (Templates/AlertDetails, Functions/_AlertDetails.pl, Functions/Sensor_Tree.pl, HeartBeat.pl) - Handle NULL values as they are no more quoted in new prelude versions 2003-09-24 : (Classes/User.pm, Functions/install_tests.pl) - Now dies when it is not able to read the Profiles/USERNAME.user file (apache not able to read it) - Add a test to index.pl and test/index.pl to check file permissions on Profiles/ directory 2003-09-23 : (Classes/User.pm, Docs/Gentoo/*) - Now display both current IP and USERNAME.user IP when then do not match (for debugging purpose) - Add CVS ebuilds for prelude and piwi (were removed from Portage) 2003-09-18 : (TopAttackers.pl, TopAttacks.pl, Functions/pie.pl, Functions/ps.pl, Docs/INSTALL-gentoo.txt) - Add preliminary postscript back-end to TopAttacks.pl (use ?backend=PS) - Add preliminary gentoo specific installation instructions 2003-09-12 : (Classes/User.pm) - Add UserName parsing when using some SSL/LDAP/Certificates to login Code contributed by Olaf Gellert (Thanks guy) 2003-09-04 : (Templates/AlertDetails) - Bug in external link generation Fixed by Nicolas Delon 2003-07-28 : (Functions/_AlertDetails.pl, AlertDetails.pl) - Yoann changed AlertDetail.pl layout 2003-07-23 : - DBD::mysql 2.9002 won't work with piwi, i'm working on it http://rt.cpan.org/NoAuth/Bug.html?ShowHeaders=3016&id=3016 - changed the $sth->execute(x,y); syntax for : $sth->bind_param(1,x, {TYPE => DBI::SQL_INTEGER }); $sth->bind_param(2,y, {TYPE => DBI::SQL_INTEGER }); $sth->execute(); - started integrating sensor-tree (see Sensor_Tree.pl) into Filters.pl 2003-06-16 : v0.8.0.0 - Yoann added some information to AlertList page and changed layout a bit - Thanks to Landmir, we're now able to sort by timestamp while grouping 2003-06-08 : - HeartBeat page now looks better under IE (only tested under Mozilla before) - HeartBeat page auto-refreshes itself, see $conf{'refresh'} in config. file (same as for AlertList/Filters.pl page) - Until i rewrite AUTH from scratch, index.pl page would directly redirect to Filters.pl page (i does nothing but disturbing people for now) - Nb Results by page was not kept when filtering after grouping (nb_resbypage overriden by nb_resbygroup), fixed - index.pl page now check for current configuration, redirects to Filters.pl if OK but on test/index.pl on failure (misconfiguration/installation problem) 2003-06-07 : - new HeartBeat / Sensor status page. replaces the old one which was pure crap (and not very usable) see new HeartBeat.pl file 2003-06-05 : - added a new configuration option : GMTdiff (difference from GMT to LocalTime, used for AlertList display and upcoming new HeartBeat page) was first requested by Patrick Erler, a long time ago 2003-06-04 : the "group me crazy" release - complete rewrite of the grouping functions. should now be faster could now navigate between pages while grouping could also group by Impact.severity, Analyzer.model, Analyzer.analyzerid and Target Address ... more to come - new configuration options (to change default element nb per page) 2003-06-03 : - changed piwi graphical style a bit. New theme by Orlin DAMYANOV from GrandLink Network (grandlink.org) 2003-05-27 : - display CreateTime instead of DetectTime when DetectTime is missing (optionnal field) 2003-05-23 : - changed the way alerts with multiple Classification objects are handled (problem seen with patched snort as the sensor) 2003-05-21 : - add some tests in Stats.pl page on 'From' and 'To' parameters format 2003-05-20 : - IPv6 addresses could also contain some '.', when using IPv4 compat. addresses. so, changed regexs in rules.pl 2003-05-14 : - script extension was hardcoded in index.pl (dummy auth page) fixed bug reported by girona (uses fnord as web server, so CGI=.cgi only) same for several other pages - add some tips to rules.pl (LML ruleset builder) - use \w instead of [A-Za-z\d] in rules 2003-04-26 : - integrated external processing code from Olaf GELLERT 2003-04-25 : - in packet view, some field were not visible (white on white) => changed hard-coded colors into a new style in .css file YEP, same changelog entry as 2003-03-26 (i forgot UDP packets) - added Attack Type number and Target number collumns to TopAttackers page (mainly to test my attacker scoring routines) - fixed Payload Hexa+ASCII Dump display when it contained HTML (AlertDetails*.pl) - remove a duplicated function 2003-04-24 : - support IPv4 DF (Don't Fragment) flag in AlertDetails/packet view - provide defaults for dbhost (localhost), dbname (prelude), dbuser (prelude) - add a check for GD::Graph in HeartBeat page (do not display graph if module missing) - add an INSTALLATION TEST PAGE (/test/index.pl) that would tell you what is wrong 2003-04-23 : - mark perl module Date::Calc as mandatory - now checks for GD::Graph in Stats.pl page - refine error messages : divide it in 2 categories : debug & error. debug are displayed only when debug=1 in config file. error are always displayed. - now complains on the screen if there is a problem connecting to the DB (mostly a misconfiguration in Functions/config.pl) 2003-04-21 : - seems PostgreSQL users have reasons to hate me : "ERROR: Argument of AND must be type boolean, not type integer". fixed - other Pg specific bug in HeartBeat page. partially fixed. it displays the page at least (internal server error before) - a bunch of code clean-up everywhere but nothing to notice on user side 2003-03-26 : - in packet view, some field were not visible (white on white) => changed hard-coded colors into a new style in .css file 2003-03-21 : - fix TopAttack*s crash bug 2003-03-03 : - added current page number. requested by Guillaume LEHMANN 2003-02-12 : - seems latest release was for perl 5.8 users only. fixed it 2003-02-08 : - massive library reorganization - two people using the same username won't make conflicting Temp files anymore 2003-02-07 - Start of the new Login dialog. (type anything in log & pass for now) - now won't complain if you haven't got GD::Graph or GD::Graph3d in Statistics 2003-02-06 : - massive HTML code clean-up 2003-02-05 : - code fusion everywhere. index.pl now redirects to Filters.pl - graph label bug (in statistics) is fixed (labels are back) 2003-02-04 : - more code cleanup - basic sorting for grouping aware views (index.pl & Filters.pl) 2003-02-03 : - fixed some nasty name-space bugs with mod_perl that came with yesterday big release. if still problems with mod_perl, please switch to CGI mode until fixed - now use modules 'strict' and 'warnings' everywhere 2003-02-02 : - name resolution could be turned off (see config.pl) - no more send your page as Referer header when external link - new cron job script to update ettercap DB files periodically - added some Grouping functions to index.pl page (CPU intensive) 2003-02-01 : - added first draft for User-Profiles. only access restricted by IP for now for more info, read Docs/user_file_format.txt and Profiles/guest.user - added time-based statistics to Filters.pl page for stored filters (.flt) - more info extracted from IP headers in packet view - possibility to delete alerts by filter if User-Profile allows it 2003-01-31 : - added ethernet card vendor lookup code from Laurent Oudot (see packet view) 2003-01-30 : - code is now in CVS - Yoann and girona identified a bug with debian perl ("Inappropriate ioctl for device" on open ). fixed - Yoann corrected some bugs in my code in HeartBeat.pl 2003-01-29 : - started working on user-profiles/management - avoid an image caching artefact in TopAttackers 2003-01-28 : - new page : Heart Beat, see if sensors are alive or not (for Yoann) - corrected Heart Beat graph, newer heartbeat on the right - TopAttackers page now show Sources (Attackers) by Default 2003-01-25 : - bug-fixes : - filters could not be saved - page navigation was not working anymore in Filters view - gave 2 data series to pie chart in TopAttack[er]s (1 only displayed) - do not display table header any more if no data in table - stats not yet an official feature, please be patient and you'll be happy 2003-01-24 : - still some code clean-up - started working on time-based statistics. more to say later 2003-01-23 : - major filter code rewrite. bugs arround, better wait one day or two. 2003-01-22 : - now encodes < and > in packet PayLoad to avoid included text to be interpreted (for Alexandre Laffont) - one more new view for AlertDetails. this time, it is packet view (who said useless ?) fields not yet extracted are in red 2003-01-21 : - did not realise that my error_log was full of warnings. little less now - changed archive format to .tar.gz (to make toady happy ;) ) - display every Classification.name in Alert lists, not only first (for Voisin) - some code clean-up in db.pl (remove lots of ugly 'if') 2003-01-20 : - to ease IDMEF understanding, there is now a new way to see AlertDetails. In AlertDetails.pl page, click "See plain XML version" and enjoy IDMEF - added a refresh on AlertList. associated configuration directive is $conf{'refresh'} => Eric Belhomme (fr.comp.securite) - a new layout for AlertLists. one alert per line (3 lines per alert before) and more info. => $conf{'AlertList_style'} 2003-01-19 : ("PostgreSQL also exists but my Front-End did not run with it" edition) - added 'dbport' configuration option, if your DB server is not listening to its default port (3306 for mysql) - added 'extension' config. option for those that want scripts to have another extension (.pl as default) - workaround for several PostgreSQL problems (connection string and LIMIT syntax, TopAttackers GROUP BY thanks to krzyzstof) - do not display anymore 'Source/Target' column in TopAttackers.pl if we only display Sources or only Targets - changed all 'Cnt' aliases in queries (TopAttackers & TopAttack) because DBD::Pg is buggy and returns 'cnt' (in lower-case) as field name => DBD::Pg bug - changed extra/nsr2flt.pl to put REPORT entries in red as those are security holes. (INFO entries do not change) 2003-01-18 : - finished the nsr2flt script. (generates filters based on a nessus report) usage : perl extra/nsr2flt.pl nessus_report.nsr generated/Filters/ (idea taken from Laurent Oudot's nessus correlation scripts) - made filter comments multiline (needed for nessus comments) - implemented the Front-End part of 'passive source machine OS fingerprint lookup' this needs a version of Prelude not yet released (patched by Laurent Oudot, not yet in CVS) that would store the attacker OS fingerprint in a new AdditionalData field 2003-01-17 : - improved the LML .rules factory with some 'meta' : just place $PORT, $PID, $IP, $HOSTNAME and it would replace them with their regex equivalent - did a command line equivalent (extra/transform.pl) => requested by Vincent Glaume - added the 'M' operator (and counterpart !M) to FilterFactory. use '%' as a wildcard 2003-01-16 : - updated the ssh .rules file to add informations that were in the log but not in prelude stored data 2003-01-15a : - got rid of every 'local $::var' declarations and added some 'undef $var'. should remove most mod_perl caching problems (under Apache::PerlRun, still problems with Apache::Registry) - when a filter is not valid (generates bad SQL), don't try to display results and only allow edition or deletion - a new tool is born : LML regex tester. just click on '*' in the Link bar 2003-01-15 : - some work to ease templating in AlertList and AlertDetails - display service name if known, next to tcp/udp port on AlertList - display 'unknown' instead of nothing when source/target address is not known - correlation on TCP/UDP port (just click a port number) - correlation for Classification.name, Source/Target Address/Port, Impact.severity, Service.protocol now also possible from AlertDetails page - seems operator > and < were not working => fixed 2003-01-13 : - new documentation about the filter file format : Docs/flt_file_format.txt - crontab/cleanup_db.pl now display an 'usage' message when miss-used - warn user to change the chwon line in INSTALL.txt if apache user isn't nobody.nobody - added a BUGS.txt in Docs directory - marqued Apache::DBI as optional in INSTALL.txt when using mod_perl 2003-01-12 : - you can now delete alerts from the DB using filters : (yep, those .flt files generated by the 'Filter Factory') $perl crontab/cleanup_db.pl generated/Filters/ICMP.flt a) this script is intended to be used from a cron job or by hand !!! b) you can use it with several .flt at a time (for batch cleanup) c) deleting is known to be sslllooowwww, it can't be sped up (not much at least) - added number of alerts/attacks per filter on "Filter Factory" page - changed AlertList presentation a bit. - Payload Hexadecimal Dump was really badly displayed because of non-proportional font => fixed + added an ASCII only version (thanks docelic) - in AlertList and Filters, clicking the attack name (Classification.name) now displays a filter based on this name. => same system for Source & Target Address => also added this to TopAttackers & TopAttack views - make use of DBI quote method, should be safer. also encodes URL a little (to avoid spaces and other chars that would break URLs) - allow negation in filter formula "(A AND !B)" or "NOT (A AND B)" 2003-01-11 : - custom Filter view now allow multi-criteria filters - added a Filter list in the link bar, on top of every page for quick access - possibility to add/concat filters together to make a new one (requested by krzysztof) - some interface clean-up 2003-01-10 : - added a new filter to TopAttackers, to choose Source/Target/Both - added cleanup_db.pl in ./crontab/ to help deleting false positives - added png_gen_test.pl in ./test/ to test image generation from browser - remove '-Tw' and 'use strict;' from perl script to avoid too much warnings - added a custom Filter view (would evolve in the future) - now display IP address instead of 'n/a' in graphic when non-resolved 2003-01-09 : - take real informations for AdditionalData in AlertDetail (girona) - added a config option $::debug => toggles perl debug on screen - move all config. directive from $::XXX to $conf{'XXX'} -> cleaner (docelic) - if GD::Graph was missing, displayed static PNG in TopAttackers -> fixed (girona) - now warns the user when it can't generate graphs because of improper rights on image directory (girona) - now warns when libgd was compiled without freetype support 2003-01-08 : Initial public release piwi/Docs/nsr_file_format.txt0000600000000000000000000000172307616060233016564 0ustar rootroot00000000000000 DESCRIPTION OF THE NSR FILE FORMAT $Id: nsr_file_format.txt,v 1.1 2003/01/29 23:15:40 leroutier Exp $ The .nsr file format was designed to facilitate the export of Nessusd reports to other tools. The format is the following for each line : 'hostname|port' (1) or 'hostname|port|script_id|type|data' (2) The format (1) indicates that a port is open. The format (2) adds a security report to the information hostname : the host name or IP address port : the port affected. The format is : 'portname (num/protocol)', ie : www (80/tcp). It can also be 'general/protocol', which means that the protocol itself is affected script_id : is the number of the script which generated the information. see http://cvs.nessus.org/plugins/search.html to find the name of a plugin thanks to its id type : either INFO (security warning) or REPORT (security hole) data : content of the report or warning. All the '\n' chars are replaced by ';' piwi/Docs/INSTALL-debian.txt0000600000000000000000000000055510007224377015742 0ustar rootroot00000000000000GD : libgd2 libgd2-dev libgd-perl ==================== PS : ghostscript (with jpeg support) ==================== PDF::API2 ==================== CGI ==================== GeoIP : geoip-bin - IP lookup command line tools that use the GeoIP library libgeoip-dev - Development files for the GeoIP library libgeoip1 - A non-DNS IP-to-country resolver library piwi/Docs/INSTALL.txt0000600000000000000000000001104610007224377014517 0ustar rootroot00000000000000Installation instructions : create the dir where you'll put the front-end : => mkdir piwi copy the archive you just downloaded to it : => cp piwi-latest.tar.gz piwi/ go to this dir : => cd piwi/ ------------------------------------------------------------------------ uncompress the full package to its destination directory. => tar -xzvf piwi-latest.tar.gz or if you have a really old tar that don't support 'z' : => gunzip piwi-latest.tar.gz => tar -xvf piwi-latest.tar ------------------------------------------------------------------------ change rights on sub-dir generated/ (must be writable for apache user) => chown -R nobody.nobody generated/ of course, if your apache user isn't 'nobody', group 'nobody', change as appropriate (wwwuser.nogroup on some distributions like Suse) (apache.apache on some distributions like MDK9.1, gentoo) ------------------------------------------------------------------------ change DB access properties in sub-dir Functions, file config.pl => dbtype : 'mysql' OR 'Pg' => dbname : Prelude DB back-end DBname => dbhost : localhost or DB server IP => dbport : port the DB server is listening on => dboptions : leave empty if you don't know => dblogin : username to connect with => dbpasswd : corresponding password in default config file, there is a mysql specific dboption : mysql_compress=1 it just compress data exchanged between localhost and the DB. usefull if slow link => if both front-end and DB are on the same host, no need of it => debug : set to 1 to have error messages displayed to screen (to debug only) => extension : contains the extension (with '.' before) of scripts (.pl is default) => ettercap_fp_db : path to ettercap OS fingerprint DB => ettercap_mac_db : path to ettercap MAC Vendor DB => HostName_Lookup : enable/disable hostname lookups => nb_resbypage : default element number by page in Alert List (either AlertNb/page or GroupNb/page when grouping) => nb_resbygroup : default alert number by group in Alert List when grouping (set to 0 to hide alerts) => nb_topattack*s : default elements listed in TopAttack*s pages => GMTdiff : As prelude stores all datetime in GMT internally, put it to 0 to display GMT, +2 if you are GMT+2, ... ------------------------------------------------------------------------ change apache config file (httpd.conf/apache2.conf) to make .pl files executable as CGI : here is the example to use with mod_perl enabled. Only write first line if Apache::DBI is installed on your system !! PerlModule Apache::DBI SetHandler perl-script PerlHandler Apache::PerlRun PerlSendHeader On without mod_perl : Options ExecCGI AddHandler cgi-script .pl in both case, don't forget to put the following line : DirectoryIndex index.pl but please, never use something like that : ScriptAlias "/real_path_to_piwi_directory/" piwi because apache would try execute any file as if they were scripts (including .css and images) ------------------------------------------------------------------------ Requirements : - a working prelude installation with DB back-end enabled (not necessary on the same host) tested under mysql v3.23/4.0.11 and PostgreSQL v7.3.x - linux 2.x or freebsd 4.7 - apache 1.3.x or 2.x (reported to work with fnord too) - perl 5.6.x or + (tested with 5.6.x & 5.8.x) - DBI module - DBD module for mysql or Pg (PostgreSQL) Avoid DBD::mysql v2.9002, it won't work !!!!! - Date::Calc : for date calculations http://search.cpan.org/author/STBEY/ - CGI Optional modules : - Geo::IP : for Country resolution from IP address (both C lib and perl module) http://www.maxmind.com/app/linux GD back-end : (deprecated) - GD, GD::Text, GD::Graph & GD::Graph3d : for graphics generation & statistics http://www.boutell.com/ -> gd C lib (with png support !!!) http://stein.cshl.org/WWW/software/GD/ -> GD http://search.cpan.org/author/MVERB/ -> GD::Graph & GD::Text PS back-end : (prefered) - ghostscript with jpeg support (for graph generation from postscript .ps files) - PDF::API2 (perl module for PDF report generation) - mod_perl : to enable perl script caching http://perl.httpd.org/ - Apache::DBI : to enable persistant DB connections http://search.cpan.org/author/ABH/ TO TEST YOUR INSTALLATION, GO DIRECTLY TO : $piwi_directory/test/index.pl piwi/test/0000700000000000000000000000000010154737620012736 5ustar rootroot00000000000000piwi/test/ENV.pl0000700000000000000000000000023707617572640013741 0ustar rootroot00000000000000#! /usr/bin/perl -w use strict; use warnings; print "Content-Type: text/html\n\n"; foreach my $Key (sort keys %ENV) { print "$Key : $ENV{$Key}
\n"; } piwi/test/png_gen_test.pl0000700000000000000000000000152207620507114015747 0ustar rootroot00000000000000#! /usr/bin/perl -w use strict; use warnings; use GD::Graph::pie; my $graph = GD::Graph::pie->new(450, 300); if ($graph->can_do_ttf()) { my @data = ( ["1st","2nd","3rd","4th","5th","6th","7th", "8th", "9th"], [ 1, 2, 5, 6, 3, 1.5, 1, 3, 4], [ sort { $a <=> $b } (1, 2, 5, 6, 3, 1.5, 1, 3, 4) ] ); $graph->set( label => 'label', transparent => 0, interlaced => 1 ); # Marges oů on ne dessine rien : # t_margin # b_margin # l_margin # r_margin # logo : # logo # logo_resize # logo_position my $gd=$graph->plot(\@data); # Convert the image to PNG and print it on standard output print "Content-Type: image/png\n\n"; print $gd->png; } else { print "Content-Type: text/html\n\n"; print "No TTF support compiled in GD
\n"; } piwi/test/index.pl0000700000000000000000000000167207770450405014416 0ustar rootroot00000000000000#!/usr/bin/perl require '../Functions/db.pl'; require '../Functions/config.pl'; require '../Functions/install_tests.pl'; our %conf = (); LoadConfig(); print "Pragma: no-cache\n"; print "Expires: -1\n"; print "Cache-Control: no-cache\n"; print "Content-Type: text/html\n\n"; print "Installation check\n"; print "Mandatory perl modules :
\n
\n"; test_PerlModules_Mandatory(); print "
\n"; print "Optionnal perl modules :
\n
\n"; test_PerlModules_Optionnal(); print "
\n"; print "Additional tests :
\n
\n"; test_write_permissions( '..' ); test_db_access(); test_password_protection(); print ""; sub my_print($$$) { my $color = shift; my $label = shift; my $text = shift; print ""; if ( $color eq 'red' ) {print "";}; print $label; if ( $color eq 'red' ) {print "";}; print " : "; print "$text
\n"; } piwi/crontab/0000700000000000000000000000000010154737621013410 5ustar rootroot00000000000000piwi/crontab/update_db_files.pl0000600000000000000000000000107607770450405017066 0ustar rootroot00000000000000#! /usr/bin/perl -w use strict; use warnings; our $wget_PATH = 'wget'; print "\n\n"; &fetch_file( 'http://cvs.sourceforge.net/viewcvs.py/*checkout*/ettercap/ettercap/etter.passive.os.fp?rev=HEAD&content-type=text/plain','generated/DB/etter.passive.os.fp' ); print "\n\n"; &fetch_file( 'http://cvs.sourceforge.net/viewcvs.py/*checkout*/ettercap/ettercap/share/mac-fingerprints?rev=HEAD&content-type=text/plain','generated/DB/mac-fingerprints' ); print "\n\n"; sub fetch_file($$) { my $URL = shift; my $Path = shift; print `$wget_PATH -N \"$URL\" -O \"$Path\"`; } piwi/crontab/report.pl0000700000000000000000000000750710003102373015253 0ustar rootroot00000000000000#!/usr/bin/perl -w use strict; use warnings; use Date::Calc; use CGI; use PDF::API2; require 'Classes/Statistic.pm'; package main; require 'Functions/config.pl'; require 'Functions/db.pl'; require 'Functions/parser.pl'; require 'Functions/console.pl'; require 'Functions/ps.pl'; require 'Functions/pdf_report.pl'; my $ReportName = shift; # PDF report name my $Type = shift; # Day (YYYY-MM-DD), Week, Month (YYYY-MM), Year (YYYY) my $From = shift; # Start boundary my $To = shift; # End boundary # Check for missing values : if ( ! $ReportName or ! $Type or ! $From or ! $To ) { die( "usage : perl ./crontab/report.pl \"2003-10 Monthly report\" \"YYYY-MM-DD\" \"2003-10-01\" \"2003-10-31\"\n" ); } # Check time values for format error : my $regex = $Type; $regex =~ s/[YMDHS]/\\d/g; if ( ( $From !~ m/$regex/ ) or ( $To !~ m/$regex/ ) ) { die( "Start and/or end period do not respect the time format\n" ); } # Create the PDF object : my $pdf = PDF::API2->new; # Set document preferences : $pdf->preferences( -singlepage => 1, -fitwindow => 1, -centerwindow => 1, -displaytitle =>1 ); # Set document information : $pdf->info( 'Author' => "StĂŠphane LOEUILLET", # 'CreationDate' => "D:20020911000000+01'00'", # 'ModDate' => "D:YYYYMMDDhhmmssOHH'mm'", 'Creator' => "PIWI - Prelude IDS Perl Web Front-End", 'Producer' => "PDF::API2", 'Title' => "$ReportName from $From to $To", 'Subject' => "$ReportName from $From to $To", 'Keywords' => "all good things are PDF" ); ################################################################# ################################################################# # Set default parameters for all pages : my $Parameters = {}; # Set generated image properties : $Parameters->{'Graph_Width'} = 800; $Parameters->{'Graph_Height'} = 600; # Set if we want a pie chart or a bar histogram : $Parameters->{'Graph_Type'} = 'bars'; # Set max element number in 'Top' Stat-Type : $Parameters->{'Top_Limit'} = 20; my $pages = []; my $new_page = { 'page_type' => 1, 'section_id' => 0 }; ################################################################# ################################################################# our %conf; # configuration directives LoadConfig(); #$conf{'debug'} = 1; # Open the DB connection : our $dbh = DB_Open(); our $cgi = CGI->new(); $cgi->param( 'backend', 'PS' ); ################################################################# ################################################################# local *FilterDir; opendir( FilterDir, 'generated/Filters/' ); foreach my $DirEntry ( sort readdir( FilterDir ) ) { if ( $DirEntry =~ m/^(.*)\.flt$/ ) { my $Label = $1; my $FilterFile = "generated/Filters/$Label.flt"; print "Processing $FilterFile\n"; # Load the Filter object from a filter file : my $Filter = Filter->new(); $Filter->load( $FilterFile ); generate_report_statistic_page( { 'Statistic_Stat_Type' => 'Time', 'Statistic_Time_Type' => $Type, 'Statistic_Time_From' => $From, 'Statistic_Time_To' => $To, 'Statistic_Filter' => $Filter, 'Statistic_Parameters' => $Parameters, 'PDF' => $pdf, 'PDF_Pages' => $pages, 'PDF_Page_Template' => $new_page, 'PDF_Page_Title' => $Label } ); } } closedir( FilterDir ); ################################################################# ################################################################# # Get total page number in the PDF : my $pagenumber = $pdf->pages; print "This PDF contains $pagenumber page(s)\n"; # Save the PDF to disk : $pdf->saveas( "generated/Reports/$ReportName.pdf" ); # Destroy the PDF object : $pdf->end; # Delete the graphs : delete_tmp_images( 'generated/Images/' ); ################################################################# ################################################################# exit; __END__ piwi/crontab/toady.pl0000600000000000000000000000140107770450405015065 0ustar rootroot00000000000000#! /usr/bin/perl -w use strict; use warnings; use DBI; require 'Classes/Filter.pm'; require 'Functions/config.pl'; require 'Functions/db.pl'; require 'Functions/FilterList.pl'; package main; if ( ! $ARGV[0] ) {die( "usage: perl crontab/toady.pl Filter.flt\n" );}; our %conf = (); # configuration directives LoadConfig(); # Open the DB connection : our $dbh = DB_Open(); while( my $FilterFile = shift ) { if ( -f $FilterFile ) { my $Filter = Filter->new(); $Filter->load( $FilterFile ); my $TotalResultNb = $Filter->count(); if ( $TotalResultNb > 0 ) { print " $TotalResultNb alerts match the following rule/filter : $FilterFile\n"; print ' '.( $Filter->comment() )."\n"; } } else { print " Filter not found : $FilterFile\n"; } } piwi/crontab/cleanup_db.pl0000600000000000000000000000131307770450405016043 0ustar rootroot00000000000000#! /usr/bin/perl -w use strict; use warnings; use DBI; require 'Functions/config.pl'; require 'Functions/db.pl'; require 'Functions/FilterList.pl'; require 'Functions/Delete.pl'; require 'Classes/Filter.pm'; package main; if ( ! $ARGV[0] ) {die( "usage: perl crontab/cleanup_db.pl Filter.flt\n" );}; our %conf = (); # configuration directives LoadConfig(); # Open the DB connection : our $dbh = DB_Open(); while( my $FilterFile = shift ) { if ( -f $FilterFile ) { my $Filter = Filter->new(); $Filter->load( $FilterFile ); my $Nb = $Filter->DeleteAlerts(); print " $Nb alerts removed by the following rule/filter : $FilterFile\n"; } else { print " Filter not found : $FilterFile\n"; } } piwi/crontab/delete_alerts_older_than.pl0000600000000000000000000000353010002124426020744 0ustar rootroot00000000000000#! /usr/bin/perl -w use strict; use warnings; use Date::Calc; use DBI; require 'Functions/config.pl'; require 'Functions/db.pl'; require 'Functions/Delete.pl'; require 'Functions/FilterList.pl'; require 'Classes/Filter.pm'; package main; ################################################################################### my $param = shift; if ( ! $param ) { die( " usage : perl ./crontab/delete_alerts_older_than.pl \"time_unit\"\n where time_unit consist of a number followed by one of those letters :\n Y (year), M (month), D (day), W (week), h (hour), m (minute) or s (second)\n\n \n Examples : 1W => 1 week / 1Y6M => 1 year and 6 monthes which could also be written 18M\n" ); }; my ( $years, $monthes, $days, $hours, $minutes, $seconds ) = ( 0, 0, 0, 0, 0, 0 ); if ( $param =~ m/(\d+)Y/i ) {$years = $1;}; if ( $param =~ m/(\d+)M/ ) {$monthes = $1;}; if ( $param =~ m/(\d+)W/i ) {$days += $1*7;}; if ( $param =~ m/(\d+)D/i ) {$days += $1;}; if ( $param =~ m/(\d+)h/i ) {$hours = $1;}; if ( $param =~ m/(\d+)m/ ) {$minutes = $1;}; if ( $param =~ m/(\d+)s/i ) {$seconds = $1;}; my $TimeStamp = sprintf( "%04d-%02d-%02d %02d:%02d:%02d", Date::Calc::Add_Delta_YMDHMS( Date::Calc::Today(), Date::Calc::Now(), -$years, -$monthes, -$days, -$hours, -$minutes, -$seconds) ); ################################################################################### our %conf = (); # configuration directives LoadConfig(); # Open the DB connection : our $dbh = DB_Open(); my $Filter = Filter->new(); my $Criteria = Criteria->new(); $Criteria->Table( 'CreateTime' ); $Criteria->Field( 'time' ); $Criteria->Operator( '<' ); $Criteria->Value( $TimeStamp ); $Filter->add_Criteria( $Criteria ); $Filter->Formula( 'A' ); my $Nb = $Filter->DeleteAlerts(); print " $Nb alerts matching $param were removed (older than $TimeStamp)\n"; piwi/AlertDetails_Packet.pl0000700000000000000000000000514310010535701016151 0ustar rootroot00000000000000#! /usr/bin/perl -w use strict; use warnings; use CGI; use DBI; use Classes::User; package main; require 'Functions/config.pl'; require 'Functions/db.pl'; require 'Functions/parser.pl'; require 'Functions/web.pl'; require 'Functions/encode.pl'; require 'Functions/packet.pl'; require 'Functions/FakeFunctions.pl'; require 'Functions/_AlertDetails.pl'; our $CurUser = User->new()->auth(); our %conf = (); # configuration directives our $cgi = ''; # CGI data LoadConfig(); print "Pragma: no-cache\n"; print "Expires: -1\n"; print "Cache-Control: no-cache\n"; print "Content-Type: text/html\n\n"; # Open the DB connection : our $dbh = DB_Open(); # Import CGI parameters : $cgi = CGI->new(); our $PageTitle = " - Alert's Details (Packet)"; ParseComponent( 'CommonHeader' ); ParseComponent( 'Links' ); our $AlertId = int( $cgi->param( 'id' ) ); print<<"EOF"; Standard / XML / Packet

EOF my $Style = $cgi->param( 'style' ); if ( ! defined( $Style ) ) {$Style = 'STD';}; my %Output; my %Proto; my @Results = get_Data( 'Alert/AdditionalData', $AlertId, 'ALL' ); foreach my $LineNum ( 1..$Results[0] ) { my %Res = get_DataLine( \@Results, $LineNum ); if ( $Res{'meaning'} eq 'Ethernet header' ) { $Proto{'2'} = 'ETH'; $Output{'2'} = Packet_Ethernet( $Res{'data'}, $Style ); } if ( $Res{'meaning'} eq 'Arp header' ) { $Proto{'3'} = 'ARP'; $Output{'3'} = Packet_ARP( $Res{'data'}, $Style ); } if ( $Res{'meaning'} eq 'Ip header' ) { $Proto{'3'} = 'IP'; $Output{'3'} = Packet_IPv4( $Res{'data'}, $Style ); } if ( $Res{'meaning'} eq 'Tcp header' ) { $Proto{'4'} = 'TCP'; $Output{'4'} = Packet_TCP( $Res{'data'}, $Style ); } if ( $Res{'meaning'} eq 'Udp header' ) { $Proto{'4'} = 'UDP'; $Output{'4'} = Packet_UDP( $Res{'data'}, $Style ); } if ( $Res{'meaning'} eq 'Icmp header' ) { $Proto{'4'} = 'ICMP'; $Output{'4'} = Packet_ICMP( $Res{'data'}, $Style ); } if ( $Res{'meaning'} eq 'Payload Hexadecimal Dump' ) { $Proto{'5'} = 'App'; $Res{'data'} =~ s//>/g; $Output{'5'} = "
$Res{'data'}
"; } if ( $Res{'meaning'} eq 'Packet Payload' ) { $Proto{'5'} = 'App'; $Res{'data'} = packet_payload__ascii_only( $Res{'data'} ); $Output{'5'} = "
$Res{'data'}
"; } } print "\n"; foreach my $Level ( 2..5 ) { if ( $Proto{$Level} ) { print<<"EOB"; EOB } } print "
$Proto{$Level} $Output{$Level}
\n"; ParseComponent( 'CommonFooter' ); piwi/AlertDetails_XML.pl0000700000000000000000000000407110003123715015401 0ustar rootroot00000000000000#! /usr/bin/perl -w use strict; use warnings; use CGI; use DBI; use Classes::User; package main; require 'Functions/config.pl'; require 'Functions/db.pl'; require 'Functions/parser.pl'; require 'Functions/web.pl'; require 'Functions/encode.pl'; require 'Functions/FakeFunctions.pl'; require 'Functions/_AlertDetails_XML.pl'; our $CurUser = User->new()->auth(); our %conf = (); # configuration directives our $cgi = ''; # CGI data LoadConfig(); print "Pragma: no-cache\n"; print "Expires: -1\n"; print "Cache-Control: no-cache\n"; print "Content-Type: text/html\n\n"; # Open the DB connection : our $dbh = DB_Open(); # Import CGI parameters : $cgi = CGI->new(); our $PageTitle = " - Alert's Details (XML/IDMEF)"; ParseComponent( 'CommonHeader' ); ParseComponent( 'Links' ); our $AlertId = int( $cgi->param( 'id' ) ); print<<"EOF"; Standard / XML / Packet

EOF my @Path = (); my %Exclude = ( 'parent_type', 1, 'parent_ident', 1, 'alert_ident', 1 ); my %Path = (); my %ResNb = (); my %Output = (); local *XMLStruct; open( XMLStruct, 'Struct.xml' ); while( my $Line = ) { foreach my $Elt ( split( />
\n"; if ( $ResNb{$Path} ) { print $Output{$Path}; } pop @Path; } else { push @Path, $Tag; my $Indent = $#Path; my $Path = join( '/', @Path ); $Output{$Path} = '  'x$Indent; $Output{$Path} .= '<'.$Path[$Indent].">
\n"; my $Output; ( $ResNb{$Path}, $Output ) = ShowValues( \@Path ); $Output{$Path} .= $Output; if ( $ResNb{$Path} ) { print $Output{$Path}; } } } } } close( XMLStruct ); undef @Path; ParseComponent( 'CommonFooter' ); piwi/TopAttackers.pl0000700000000000000000000001650310003102373014710 0ustar rootroot00000000000000#! /usr/bin/perl -w use strict; use warnings; use DBI; use Classes::User; use Classes::Filter; use CGI; package main; require 'Functions/config.pl'; require 'Functions/db.pl'; require 'Functions/parser.pl'; require 'Functions/web.pl'; require 'Functions/pie.pl'; require 'Functions/encode.pl'; require 'Functions/Name_Resolution.pl'; require 'Functions/FakeFunctions.pl'; require 'Functions/score.pl'; our $CurUser = User->new()->auth(); our %conf = (); # configuration directives our %miss = (); # missing Modules (optional ones) our $cgi = ''; # CGI data eval( 'require Geo::IP' ) || ( $miss{'Geo::IP'} = 1 ); LoadConfig(); print "Pragma: no-cache\n"; print "Expires: -1\n"; print "Cache-Control: no-cache\n"; print "Content-Type: text/html\n\n"; # Open the DB connection : our $dbh = DB_Open(); # Import CGI parameters : $cgi = CGI->new(); my $Where = ''; my $Title = ''; if ( ! $cgi->param( 'f' ) ) {$cgi->param( 'f', 'S' );}; my $Type_short = $cgi->param( 'f' ); if ( $Type_short eq 'S' ) {$Where = 'WHERE parent_type=\'S\' ';$Title = 'attacker';}; if ( $Type_short eq 'T' ) {$Where = 'WHERE parent_type=\'T\' ';$Title = 'attacked host';}; if ( $Type_short eq 'All' ) {$Where = 'WHERE (parent_type=\'S\' OR parent_type=\'T\') ';$Title = 'host';}; our $PageTitle = ' - Top '.$conf{'nb_topattack*s'}.' '.$Title.' list'; ParseComponent( 'CommonHeader' ); ParseComponent( 'Links' ); ParseComponent( 'TopAttackers_Filter' ); my ( @labels, @values, @iaddr, @parent, @country ); my $First = 1; if ( ! $cgi->param( 'r' ) ) {$First = 0;}; my %CountryCount; my $Statement = 'SELECT count(address) as cnt,address,parent_type,category FROM '; $Statement .= 'Prelude_Address '.$Where; $Statement .= 'GROUP BY address,parent_type,category ORDER BY cnt DESC LIMIT '.$conf{'nb_topattack*s'}.';'; my $Sth = $dbh->prepare( $Statement ); $Sth->execute(); while( my $HashRef = $Sth->fetchrow_hashref() ) { my $iaddr = $HashRef->{'address'}; my $name = ''; if ( $conf{'HostName_Lookup'} ) { my ( $aliases, $proto ) = ( undef, undef ); if ( $HashRef->{'category'} eq 'ipv4-addr' ) { ( $name, $aliases, $proto) = MY_gethostbyaddr( $iaddr ); } } my $country = ''; if ( ! $miss{'Geo::IP'} ) { my $gi = Geo::IP->new(); $country = $gi->country_code_by_addr( $iaddr ); if ( ! $country ) {$country = 'Unk.';}; if ( ! $First ) {$CountryCount{$country} += $HashRef->{'cnt'};}; } if ( ! $First ) { push @labels, ( $name || $iaddr ); push @values, $HashRef->{'cnt'} ; push @iaddr, $iaddr; push @parent, $HashRef->{'parent_type'}; push @country, $country; } else { $First = 0; } } $Sth->finish(); if ( $cgi->param( 'r' ) ) { print "In following pie charts, the biggest 'attacker' has been removed.\n"; } my $FileExt = ''; if ( ! $cgi->param( 'backend' ) ) {$cgi->param( 'backend', $conf{'default_backend'} );}; if ( $cgi->param( 'backend' ) eq 'HTML' ) { print "\n"; print " \n"; print " \n"; if ( $Type_short eq 'S' ) { print " \n"; print " \n"; print " \n"; } print " \n"; if ( ! $miss{'Geo::IP'} ) {print " \n";}; if ( $conf{'HostName_Lookup'} ) {print " \n";}; if ( $Type_short eq 'All' ) {print " \n";}; print " \n"; for( my $cnt = 0 ; $cnt <= $#values ; $cnt ++ ) { my $name = $labels[$cnt]; my $iaddr = $iaddr[$cnt]; my $count = $values[$cnt]; my $parent = $parent[$cnt]; my $country = $country[$cnt]; print " \n"; print " \n"; if ( $Type_short eq 'S' ) { my $Source_AlertTypeNb = Source_AlertTypeNb( $iaddr ) || 1; my $Source_TargetNb = Source_TargetNb( $iaddr ) || 1; my $Score = $count/$Source_AlertTypeNb/$Source_TargetNb; print " \n"; print " \n"; print " \n"; } print " \n"; if ( ! $miss{'Geo::IP'} ) { print " \n"; } if ( $conf{'HostName_Lookup'} ) { print ' \n"; } if ( $Type_short eq 'All' ) { print " \n"; } print " \n"; } print "
AttackNb AttackTypeNb TargetNb Score  AddressCountry Host nameSource/Target
$count $Source_AlertTypeNb $Source_TargetNb $Score "; print "$iaddr$country'.( $name || 'n/a' )."$parent
\n"; } if ( $cgi->param( 'backend' ) eq 'GD' ) { eval( 'require GD::Graph::pie' ) || ( $miss{'GD::Graph'} = 1 ); if ( $miss{'GD::Graph'} ) { error( 'No graphics because module GD::Graph is missing' ); } else { my @data = ( [@labels], [@values] ); &piechart( \@data, 'top '.$Title, 'generated/Images/TopAttackers'.$Type_short.'.png' ); undef @data; $FileExt = 'png'; } } if ( $cgi->param( 'backend' ) eq 'PS' ) { require 'Functions/ps.pl'; our $PS_Title = "Top $conf{'nb_topattack*s'} ".$Title; my @data = ( [@labels], [@values], [] ); my $ res = &postscript( \@data, 'piechart.ps', 'generated/PostScript/TopAttackers.ps', 900 ); if ( $res ) { `$conf{'gs_path'} -sDEVICE=jpeg -dNOPAUSE -dBATCH -dGraphicsAlphaBits=4 -dTextAlphaBits=4 -sOutputFile="generated/Images/TopAttackers$Type_short.jpg" generated/PostScript/TopAttackers.ps`; unlink 'generated/PostScript/TopAttackers.ps'; $FileExt = 'jpg'; } } if ( ! $miss{'Geo::IP'} ) { my @labels = (); my @values = (); foreach my $Country ( sort {$CountryCount{$b} <=> $CountryCount{$a}} keys %CountryCount ) { push @labels, $Country; push @values, $CountryCount{$Country}; if ( $cgi->param( 'backend' ) eq 'GD' ) { if ( ! $miss{'GD::Graph'} ) { my @data = ( [@labels], [@values] ); &piechart( \@data, 'top '.$Title.' countries', 'generated/Images/TopAttackers_country'.$Type_short.'.png' ); undef @data; } } if ( $cgi->param( 'backend' ) eq 'PS' ) { require 'Functions/ps.pl'; our $PS_Title = "Top $conf{'nb_topattack*s'} ".$Title.' countries'; my @data = ( [@labels], [@values], [] ); my $res = &postscript( \@data, 'piechart.ps', 'generated/PostScript/TopAttackers.ps', 900 ); if ( $res ) { `$conf{'gs_path'} -sDEVICE=jpeg -dNOPAUSE -dBATCH -dGraphicsAlphaBits=4 -dTextAlphaBits=4 -sOutputFile="generated/Images/TopAttackers_country$Type_short.jpg" generated/PostScript/TopAttackers.ps`; unlink 'generated/PostScript/TopAttackers.ps'; $FileExt = 'jpg'; } } } } else { error( 'No country information because module Geo::IP is missing' ); } if ( $FileExt ) { print <<"EOF";



EOF if ( $cgi->param( 'backend' ) eq 'PS') {print "";}; if ( ! $miss{'Geo::IP'} ) { print "\n"; } if ( $cgi->param( 'backend' ) eq 'PS' ) {print "";}; print "
\"\"
"; } ParseComponent( 'CommonFooter' ); piwi/extra/0000700000000000000000000000000010154737620013102 5ustar rootroot00000000000000piwi/extra/idmef_extract.pl0000600000000000000000000000235007616060233016255 0ustar rootroot00000000000000#! /usr/bin/perl use XML::IDMEF; # We create an IDMEF object : my $tmp=''; local *Prelude_IDMEF; open(Prelude_IDMEF,'/var/log/prelude-xml.log'); while(my $str=) { $str =~ s/\r|\n/\n/g; $str =~ s/\n/<br>/g; $tmp.=$str; if ($tmp =~ m//i) { # Contains at least one complete card : $tmp =~ s/()//i; my $Card=$1; $Card =~ s/<br>/\r\n/g; my $idmef=new XML::IDMEF()->in($Card); if ($idmef->get_type() =~ m/Alert/i) { my $idmef_hash=$idmef->to_hash(); my $Number=$idmef_hash->{'Alertident'}->[0]; my $Severity=$idmef_hash->{'AlertAssessmentImpactseverity'}->[0]; my $Class=$idmef_hash->{'AlertClassificationname'}->[0]; print "$Number) $Severity - $Class\n"; =pod if (exists($idmef_hash->{'AlertAdditionalData'})) { my $AddDatas=$idmef_hash->{'AlertAdditionalData'}; if (ref($AddDatas) eq 'ARRAY') { foreach my $AddData (@{$AddDatas}) { print "$AddData\n"; } } } =cut } } } close(Prelude_IDMEF); piwi/extra/nsr2flt.pl0000600000000000000000000000255510002540573015031 0ustar rootroot00000000000000#! /usr/bin/perl -w use strict; use warnings; use Socket; require 'Classes/Filter.pm'; package main; require 'Functions/nessus.pl'; require 'Functions/console.pl'; my $nessus_report = shift; my $dest_filter_dir = shift; if ( ! $nessus_report or ! $dest_filter_dir ) { die( "usage : ./nsr2flt.pl nessus_report.nsr destination_filter_dir/\n" ); } my $callback_data = { 'nessus_allowed_types' => { 'INFO' => 1, # Security Note/Informational 'REPORT' => 1 # Security Warning/HOLE }, 'nessus_port_list' => {},# Discovered port list 'filter_directory' => $dest_filter_dir, # Directory where the generated filters would be saved 'filter_count' => 0 }; if ( -d $dest_filter_dir ) { # Create port list from nessus report file : if ( parse_nessus_nsr_file( $nessus_report, \&add_nessus_entry_to_host_port_list, $callback_data ) ) { # Create a filter for each port in the port list and save it to disk : create_filter_from_port_list( $callback_data->{'nessus_port_list'}, 'ip', \&save_generated_filter_to_disk, $callback_data ); print "\nGenerated ".( $callback_data->{'filter_count'} )." filters from this nessus report ($nessus_report)\n"; } } else { die( "This directory does not exist : $dest_filter_dir\n" ); } sub save_generated_filter_to_disk($$) { my $callback_data = shift; my $Filter = shift; $Filter->save(); $callback_data->{'filter_count'} ++; } piwi/extra/transform.pl0000600000000000000000000000072307771455540015467 0ustar rootroot00000000000000#! /usr/bin/perl my $rulesfile = shift; if ( ! $rulesfile ) {die( " usage : ./transform myrule.rules > result.rules\n" );}; if ( -f $rulesfile ) { local *RULES; open( RULES, $rulesfile ); while( my $match = ) { $match =~ s/\$IP/[\\d\\.]+|[\\dA-Fa-f\\:]+/g; $match =~ s/\$PID/-?\\d+/g; $match =~ s/\$HOSTNAME/[A-Za-z\\d\\-\\.]+/g; $match =~ s/\$PORT/\\d+/g; print $match; } close( RULES ); } else { die( "$rulesfile does not exist\n" ) } piwi/FilterList.pl0000700000000000000000000000421710003102373014364 0ustar rootroot00000000000000#! /usr/bin/perl -w use strict; use warnings; use CGI; use DBI; use Classes::Filter; use Classes::User; package main; require 'Functions/config.pl'; require 'Functions/db.pl'; require 'Functions/parser.pl'; require 'Functions/web.pl'; require 'Functions/FilterList.pl'; require 'Functions/encode.pl'; require 'Functions/FakeFunctions.pl'; our $CurUser = User->new()->auth(); our %conf = (); # configuration directives our $cgi = ''; # CGI data LoadConfig(); print "Pragma: no-cache\n"; print "Expires: -1\n"; print "Cache-Control: no-cache\n"; print "Content-Type: text/html\n\n"; # Open the DB connection : our $dbh = DB_Open(); # Import CGI parameters : $cgi = CGI->new(); our $PageTitle = ' - Filters List'; ParseComponent( 'CommonHeader' ); ParseComponent( 'Links' ); if ( $cgi->param( 'del' ) ) { DeleteFilterFile( $cgi->param( 'del' ) );}; print "Hand made filter

\n"; print "Filters available :

\n"; print "\n"; local *DIRECTORY; opendir( DIRECTORY, 'generated/Filters/' ); foreach my $DirEntry ( sort readdir( DIRECTORY ) ) { if ( $DirEntry =~ m/^(.*)\.flt$/ ) { my $FilterName = $1; my $Filter = Filter->new(); $Filter->load( 'generated/Filters/'.$FilterName.'.flt' ); my $TotalResultNb = $Filter->count(); my $Bad = 0; if ( ! defined( $TotalResultNb ) ) { $Bad = 1; }; print " "; print ""; print ""; print "'; print "'; print ''; print " \n"; } } closedir( DIRECTORY ); print "
deledit".( $Bad?'bad':$TotalResultNb ).'"; if ( ! $Bad ) { print ""; } print $FilterName; if ( ! $Bad ) {print '';}; print ''.( $Filter->comment() || ' ' ).'
\n"; ParseComponent( 'CommonFooter' ); piwi/Functions/0000700000000000000000000000000010154737621013730 5ustar rootroot00000000000000piwi/Functions/Name_Resolution.pl0000600000000000000000000000031007772601715017372 0ustar rootroot00000000000000use Socket; sub MY_gethostbyaddr($) { my $iaddr = shift; if ( $conf{'HostName_Lookup'} ) { return gethostbyaddr( inet_aton( $iaddr ), AF_INET ); } else { return ( 'n/a', '', '' ) } } 1; piwi/Functions/parser.pl0000600000000000000000000000276010010233614015550 0ustar rootroot00000000000000sub ParseComponent($) { my $Component = shift; my $ComponentDir = 'Templates/'; my $Path = $ComponentDir.'/'.$Component; $Path =~ s/\/+/\//g; local *Component; undef $!; open( Component, $Path ); if ( $! and ( $! !~ m/Inappropriate ioctl for device/i ) ) { debug( "Missing component $Path : $!" ); return 0; } else { my $Template = ''; while( my $Line = ) {$Template .= $Line;} close( Component ); $Template =~ s/\r//mg; $Template =~ s/<\?\n+//?>/mg; while( $Template ) { # Special case : $Template =~ s/<\?\?(.*?)\?\?>/get( $1 ) || ' '/meg; my ( $BeforeCode, $tmp ) = split( /<\?/m, $Template, 2 ); $Template = $tmp || ''; # Something before a tag, print it : if ( $BeforeCode ) {print $BeforeCode;}; my ( $Code, $AfterCode ) = split( /\?>/m, $Template, 2 ); $Template = $AfterCode || ''; if ( $Code ) { exec_code( $Code ); }; } } } sub exec_code($) { my $Code = shift; eval( $Code ); if ($@) { $Code =~ s//>/g; my ( $LineNb ) = ( $@ =~ m/line (\d+)/ ); if ( $LineNb ) { $LineNb -= 3; my @Code = split( /\n/, $Code ); $Code = join( "\n", @Code[ 0..( $LineNb - 3 ) ] )."\n"; $Code .= ''; $Code .= join( "\n", @Code[ ( $LineNb - 2 )..( $LineNb + 2 ) ] ); $Code .= ''; $Code .= "\n".join( "\n", @Code[ ( $LineNb + 3 )..$#Code ] ); } debug( "Error in Perl code :($@)
\n$Code" ); } } 1; piwi/Functions/Filtered_Links.pl0000600000000000000000000000757110003102373017156 0ustar rootroot00000000000000sub AlertList_otfFilt_Class_name() { my @Results = get_Data( 'Alert/Classification', $AlertId, '' ); my %Res = get_DataLine( \@Results, 1 ); my $name = $Res{'name'}; if ( $name ) { if ( ! $cgi->param( 'timelimit' ) ) {$cgi->param( 'timelimit', '10Y' );}; print "".$name.''; } else { print 'n/a'; } } sub AlertList_otfFilt_Impa_sev($) { my $Type = shift; my $Severity = get( 'Alert/Impact.severity' ); if ( $Severity ) { print ""; if ( $Type eq 'Img' ) { print "\"\""; } else { print $Severity; } print ""; } } sub AlertList_otfFilt_Impa_completion() { my $completion = get( 'Alert/Impact.completion' ); if ( $completion ) { print "".$completion.''; } else { print 'n/a'; } } sub AlertList_otfFilt_Ana_model() { my $model = get( 'Alert/Analyzer.model' ); print "".$model.''; } sub AlertList_otfFilt_Ana_class() { my $class = get( 'Alert/Analyzer.class' ); print "".$class.''; } sub AlertList_otfFilt_Serv_proto($) { my $Type = shift; if ( $Type ne 'Source' ) {$Type = 'Target';}; my $Protocol = get( 'Alert/'.lc( $Type ).'/Service.protocol' ); if ( $Protocol and ( $Protocol ne '-' ) ) { print "".$Protocol.''; } else { print 'unknown'; } } sub AlertList_Get_Addr_and_Port($$) { my $Type = shift; my $ShowService = shift; if ( ! $cgi->param( 'timelimit' ) ) {$cgi->param( 'timelimit', '1D' );}; if ( $Type ne 'Source' ) {$Type = 'Target';}; my $Address = get( 'Alert/'.lc( $Type ).'/Node/Address.address' ); if ( $Address ) { print "".$Address.''; } else { print 'unknown'; } my $Port = get( 'Alert/'.lc( $Type ).'/Service.port' ); if ( $Port ) { print " ".$Port.''; my $Proto = lc( get( 'Alert/'.lc( $Type ).'/Service.protocol' ) ); my ( $name, $aliases, $port, $proto ) = getservbyport( $Port, $Proto ); print "/".$Proto.''; if ( $name ) { print " (".$name.') '; } } } 1; piwi/Functions/db.pl0000600000000000000000000001176010010233614014641 0ustar rootroot00000000000000sub DB_Open() { # Initialize table list : %db_table_type=( 'Hearbeat' => '0', 'Alert' => '1', 'Action' => '2', 'Address' => '2.2', 'Assessment' => '2', 'Classification' => '2', 'Confidence' => '2', 'DetectTime' => '2', 'FileList' => '2', 'File' => '2', 'FileAccess' => '2', 'Impact' => '2', 'Inode' => '2', 'Linkage' => '2', 'Node' => '2.1', 'Process' => '2.1', 'ProcessArg' => '2', 'ProcessEnv' => '2', 'SNMPService' => '2', 'Service' => '2.1', 'ServicePortlist' => '2', 'Source' => '2', 'Target' => '2', 'User' => '2', 'UserId' => '2', 'WebService' => '2', 'WebServiceArg' => '2', 'AdditionalData' => '3.1', 'Analyzer' => '3', 'AnalyzerTime' => '3.1', 'CreateTime' => '3', ); # 0 : no link to an Alert # 1 : Alert itself => ident=? # 2 : Alert child only => alert_ident=? # 3 : X child => parent_type='A' AND parent_ident=? if ( ! $conf{'nb_resbypage'} ) {$conf{'nb_resbypage'} = 30;}; if ( ! defined( $conf{'nb_resbygroup'} ) ) {$conf{'nb_resbygroup'} = 5;}; if ( ! $conf{'nb_topattack*s'} ) {$conf{'nb_topattack*s'} = 15;}; # if ( ! defined( $conf{'GMTdiff'} ) ) { my $tz = `date +%z`; if ( $tz ) { my ( $sign, $h, $m ) = ( substr( $tz, 0, 1) || '+', substr( $tz, 1, 2 ), substr( $tz, 3, 2 ) ); $sign .= '1'; $conf{'GMTdiff'} = $sign * ( $h + $m/60 ); } else { $conf{'GMTdiff'} = 0; } } # if ( ! $conf{'dbhost'} ) {$conf{'dbhost'} = 'localhost';}; if ( ! $conf{'dbname'} ) {$conf{'dbname'} = 'prelude'}; if ( ! $conf{'dblogin'} ) {$conf{'dblogin'} = 'prelude'}; my $cstring = "DBI:$conf{'dbtype'}:"; if ( $conf{'dbtype'} =~ m/^mysql$/i ) { $cstring .= "database=$conf{'dbname'};host=$conf{'dbhost'}"; if ( $conf{'dbport'} ) {$cstring .= ";port=$conf{'dbport'}";}; if ( $conf{'dboptions'} ) { $cstring .= ";options=$conf{'dboptions'}"; } } if ( $conf{'dbtype'} =~ m/^pg$/i ) { $cstring .= "dbname=$conf{'dbname'};host=$conf{'dbhost'}"; if ( $conf{'dbport'} ) {$cstring .= ";port=$conf{'dbport'};";}; if ( $conf{'dboptions'} ) { $cstring .= "options=$conf{'dboptions'}"; } } # Open DB connection : return DBI->connect($cstring,$conf{'dblogin'},$conf{'dbpasswd'}) || DB_CONNECT_ERROR(DBI->errstr); } sub DB_CONNECT_ERROR($) { error( 'Problem connecting to DB : '.shift()."\n" ); exit; } sub get($) { my $Path = shift; my $Field; ( $Path, $Field ) = split( /\./, $Path ); if ( ! exists( $Cache{$Path} ) ) { my %tmp; if ( $Path eq 'Alert' ) { %tmp = ( 'ident', $AlertId ); } else { %tmp = get_Data( $Path, $AlertId, 'FIRST' ); } $Cache{$Path} = \%tmp; } return $Cache{$Path}->{$Field}; } sub LIMIT_sql() { if ($conf{'dbtype'} =~ m/^mysql$/i) { return 'LIMIT ?,?'; } if ($conf{'dbtype'} =~ m/^pg$/i) { return 'LIMIT ? OFFSET ?'; } } sub LIMIT_values($$$) { my $Sth=shift; my $Nb=shift; my $Offset=shift; if ($conf{'dbtype'} =~ m/^mysql$/i) { $Sth->bind_param(1,$Offset, { TYPE => DBI::SQL_INTEGER } ); $Sth->bind_param(2,$Nb, {TYPE => DBI::SQL_INTEGER } ); } if ($conf{'dbtype'} =~ m/^pg$/i) { $Sth->bind_param(2,$Offset,{ TYPE => DBI::SQL_INTEGER } ); $Sth->bind_param(1,$Nb,{ TYPE => DBI::SQL_INTEGER } ); } } sub get_Data($$$) { my $Path=shift; my $AlertID=int(shift); my $Type=shift; # Get table list from Data Path : my @Tables=split(/\//,$Path); # Build Table name : (the one which contains information we want) my $LastTable='Prelude_'.$Tables[$#Tables]; my $Statement="SELECT * FROM $LastTable WHERE alert_ident=?"; if ($db_table_type{$Tables[$#Tables]} =~ m/\.(\d)$/) { $Statement.=" AND parent_type='".substr($Tables[$#Tables-$1],0,1)."'"; } if ($db_table_type{$Tables[$#Tables]} =~ m/^3/) { # For type 3 tables, Alert ident is parent_ident : $Statement =~ s/alert_/parent_/; } $Statement.=';'; my $Sth=$dbh->prepare($Statement); $Sth->execute($AlertID); my $RowsNb=$Sth->rows(); my @Result=($RowsNb); if ($RowsNb) { my $First=1; my @Fields; while(my $Hash=$Sth->fetchrow_hashref()) { if ($First) { # Build field list : foreach my $Field (keys %{$Hash}) {push @Fields,$Field;}; # Result would contain field number followed by fields : @Result=($RowsNb,$#Fields+1,@Fields); $First=0; } # Add values of each line to results : foreach my $Field (@Fields) {push @Result,$Hash->{$Field};}; } } $Sth->finish(); if (!defined($Type)) {$Type='FIRST';}; if ($Type eq 'FIRST') { return get_DataLine(\@Result,1); } else { return @Result; } } sub get_DataLine($$) { my $ArrayRef=shift; my $LineNum=shift; my $LineNb=$ArrayRef->[0];if (!$LineNb) {return '-','';}; my $FieldNb=$ArrayRef->[1]; my $Offset=2+$LineNum*$FieldNb; my %Hash; for(my $i=0;$i<$FieldNb;$i++) { $Hash{$ArrayRef->[2+$i]}=$ArrayRef->[$Offset+$i]; } return %Hash; } 1; piwi/Functions/ps.pl0000600000000000000000000000762710010233614014705 0ustar rootroot00000000000000sub postscript($$$$) { my $DataRef = shift; my $Template = shift; my $FileName = shift; my $width = shift || 900; my @data = @{$DataRef}; # my $cpt = 0; my $LIMIT = 33; my $total = 0; foreach my $value ( @{$data[1]} ) { if ( ! defined( $value ) ) { debug( "postscript : \$value is not defined" ); $value = 0; }; if ( $cpt < $LIMIT ) { $total += $value; $cpt ++ } } if ( ! $total ) { return 0; }; # local $::image_width = $width; # Set histogram width : local $::histo_width = $::image_width - 100; # # get number of elements : local $element_nb = 0; foreach my $value ( @{$data[1]} ) { # % with 2 decimals : if ( $element_nb < $LIMIT ) { $data[2]->[$element_nb] = int( $value / $total * 10000 )/100; $element_nb ++; } } # my $wrap = 0; # nb of element per collumn my $spin = 0; # nb of collumns if ( ( $element_nb <= 22 ) and ! ( $element_nb % 2 ) ) { $wrap = $element_nb / 2; $spin = 2; } else { $wrap = int( $element_nb / 3 ); if ( $element_nb % 3 ) { $wrap ++; }; $spin = 3; if ( $element_nb < 3 ) {$spin = $element_nb;}; } # # Legend for both pie chart and bar histogram : local $::COMMENT = ''; for( my $cpt2 = 0 ; $cpt2 < $cpt ; $cpt2 ++ ) { # x+=200 every $wrap element : # y is the same every $wrap element : my $x = 50 + int( ( $::image_width - 10 ) / $spin ) * int( $cpt2 / $wrap ); my $y = 200 - 18 * ( $cpt2 % $wrap ); my $label = substr( $data[0]->[$cpt2] , 0, int( 60 / $spin ) ); $label =~ s/\\//g; # Keep the nb of open '(' the same as ')' or ghostscript could die : (like 7.05.6 (2003-02-05) does) my $tmp_str = $label; $tmp_str =~ s/[^\(\)]//g; my $braces_nb = length( $tmp_str ); $tmp_str =~ s/[^\(]//g; my $open_braces_nb = length( $tmp_str ); my $close_braces_nb = $braces_nb - $open_braces_nb; my $diff = $open_braces_nb - $close_braces_nb; for( my $i = 1 ; $i <= $diff ; $i++ ) { # Remove one open brace $label =~ s/\(//; $open_braces_nb --; } # I suppose this bug also exists in the opposite case : $diff = $open_braces_nb - $close_braces_nb; for( my $i = 1 ; $i <= -$diff ; $i++ ) { # Remove one close brace $label =~ s/\)//; $close_braces_nb --; } # $label .= ' ('; $label .= $data[1]->[$cpt2]; $label .= '/'; $label .= $data[2]->[$cpt2]; $label .= '%)'; $::COMMENT .= "$x $y $cpt2 ($label) comment\n"; } # local $::DATA = ''; # pie-chart labels local $::HISTO1 = ''; # histogram bars local $::HISTO2 = ''; # values printed on bars (numbers) my ( $id1, $id2 ) = ( 0, 0 ); for( my $cpt2 = 0 ; $cpt2 < $cpt ; $cpt2 ++ ) { # $cpt2 is not only color index but also x position index my $label = $data[0]->[$cpt2]; # angle calculation, for pie chart only : $id1 = $id1 + int( ( $data[2]->[$cpt2] )*360/100 ); $::DATA .= "30 $id1 $id2 $cpt2 ($label) draw_pie\n"; $id2 = $id1; # histogram only : (bar and value above the bar) $::HISTO1 .= 2 * ( $data[2]->[$cpt2] ).' '.$cpt2." histo\n"; $::HISTO2 .= 2 * ( $data[2]->[$cpt2] + $spin*( $cpt2 % 2 ) ).' '.$cpt2." (".( $data[1]->[$cpt2] ).") value\n"; } # # Histogram bar width is function of element number : local $::COLUMN_WIDTH = int( $::histo_width / 1.25 / ( ( $element_nb > 5 )?$element_nb:5 ) ); # 10 elements => 40 local $::HALF_WIDTH = int( $::COLUMN_WIDTH / 2 ); # local *TEMP_PS_FILE; open( TEMP_PS_FILE, ">$FileName" ) || error( 'Impossible to write PostScript file to disk' ); select( TEMP_PS_FILE ); ParseComponent( $Template ); select( STDOUT ); close( TEMP_PS_FILE ); undef $cpt; undef @data; return 1; } sub histogram_position_list($) { my $array_name = shift; my $interval = int( $::histo_width / $::element_nb ); # 10 elements => 50 # x position for each value : my $positions = ''; for( my $i = 0 ; $i < $::element_nb ; $i ++ ) { $positions .= 10 + $i*$interval; $positions .= "\n"; } print "/$array_name [\n$positions] def\n"; } 1; piwi/Functions/Delete.pl0000600000000000000000000000064107770703023015471 0ustar rootroot00000000000000sub DeleteAlert_by_Id($) { my $Id = shift; foreach my $Table ( keys %db_table_type ) { my $TableType = int( $db_table_type{$Table} ); my $Where = 'ident='.$Id; if ( $TableType eq 2 ) {$Where = 'alert_'.$Where;}; if ( $TableType eq 3 ) {$Where = "parent_type='A' AND parent_".$Where;}; if ( $TableType ) { $dbh->do( "DELETE FROM Prelude_$Table WHERE $Where;" ) || return 0; } } return 1; } 1; piwi/Functions/FilterList.pl0000600000000000000000000000111207772601715016351 0ustar rootroot00000000000000sub ParseFilterFile($) { my $FilterFile = shift; my %Filter = (); local *FilterFile; undef $!; open( FilterFile, $FilterFile ); if ( $! and ( $! !~ m/Inappropriate ioctl for device/i ) ) { error( "erreur d'ouverture du filtre $FilterFile : $!" ); return (); } while( my $Line = ) { $Line =~ s/\r|\n//g; if ( $Line ) { my ( $Key, $Value ) = split( /=/, $Line, 2 ); $Filter{$Key} = $Value; } } close( FilterFile ); return %Filter; } sub DeleteFilterFile($) { my $FilterFile = shift; unlink 'generated/Filters/'.$FilterFile.'.flt'; } 1; piwi/Functions/config.pl0000600000000000000000000000414510010515472015525 0ustar rootroot00000000000000sub LoadConfig() { # Database : $conf{'dbtype'} = 'mysql'; # mysql / Pg $conf{'dbname'} = 'prelude'; $conf{'dbhost'} = 'localhost'; # $conf{'dbport'} = 5432; # default mysql port is 3306 / pgsql 5432 (only uncomment if using Postgres) # $conf{'dboptions'} = 'mysql_compression=1'; # (only uncomment with mysql) $conf{'dblogin'} = 'prelude'; $conf{'dbpasswd'} = ''; ########################################################## # Other : $conf{'debug'}=0; # Debug perl code onscreen (0 or 1) $conf{'extension'}='.pl'; # scripts file extension (.pl) $conf{'refresh'}=120; # AlertList refresh in seconds (120=refresh every 2 min) $conf{'HostName_Lookup'}=1; # Host Name Resolution (0 or 1) ########################################################## $conf{'ettercap_fp_db'}='./generated/DB/etter.passive.os.fp'; $conf{'ettercap_mac_db'}='./generated/DB/mac-fingerprints'; ########################################################## # default element number by page in Alert List $conf{'nb_resbypage'}=30; # default alert number by group in Alert List when grouping (0 to hide) $conf{'nb_resbygroup'}=5; # default elements listed in TopAttack*s pages $conf{'nb_topattack*s'}=10; ########################################################## # local offset to GMT : (for France, in summer, we are on GMT+2) let it commented (#) for autodetection # $conf{'GMTdiff'}=+0; ########################################################## # Drawing back-end : (GD is deprecated, PS is the newer) $conf{'default_backend'}='PS'; # Path to ghostscript (gs) used when back-end is PS, not GD : $conf{'gs_path'}='/usr/bin/gs'; # Are graphs transparent when back-end is GD, not PS : $conf{'GD_transparent'}=0; ########################################################## # Number of heartbeat to consider per sensor : $conf{'heartbeat_nb'} = 48; # Number of errors to display before to give up : $conf{'heartbeat_max_error_count'} = 10; # Default heartbeat interval in seconds : $conf{'heartbeat_delta'} = 3600; # Nb of second before to panic on missing HeartBeat : $conf{'heartbeat_error_margin'} = 6; } 1; piwi/Functions/encode.pl0000600000000000000000000000022507707600661015526 0ustar rootroot00000000000000sub url_encode($) { my $data=shift; $data =~ s/ / /g; $data =~ s/([^A-Za-z0-9])/'%'.sprintf('%02X',(ord($1)))/ieg; return $data; } 1; piwi/Functions/install_tests.pl0000600000000000000000000001131510007224377017154 0ustar rootroot00000000000000# Mandatory perl modules : sub test_PerlModules_Mandatory() { if ( eval( 'require 5.006_000' ) ) { my_print('green','perl',"You have perl v5.6.0 or newer"); } else { my_print('red','perl',"Your perl version is too old, you need at least perl v5.6.0 ; Make 'perl -V' to knew exactly which version you have"); } if ( eval( 'require Socket' ) ) { my_print('green','Socket',"Network routines, name resolution ok"); } else { my_print('red','Socket',"Socket module is mandatory"); } if ( eval( 'require CGI' ) ) { my_print('green','CGI',"You have the CGI module"); } else { my_print('red','CGI',"You have to install the CGI module"); } if ( eval( 'require DBI' ) ) { my_print('green','DBI',"You have generic DB access module"); my $db_mysql = eval( 'require DBD::mysql' ); my $db_pgsql = eval( 'require DBD::Pg' ); if ( $db_mysql or $db_pgsql ) { my_print('green',' + DBD',"You have, at least, one specific DB access module"); } else { my_print('red',' + DBD',"Both DBD::mysql and DBD::Pg are missing. you need at least one to access to prelude DB"); } } else { my_print('red','DBI',"Generic database access module : DBI is not installed"); } if ( eval( 'require Date::Calc' ) ) { my_print('green','Date::Calc',"Date manipulations"); } else { my_print('red','Date::Calc',"Date manipulations"); } } # Optionnal perl modules : sub test_PerlModules_Optionnal() { if ( eval( 'require Geo::IP' ) ) { my_print('green','Geo::IP',"Country look-up for an IP address"); } else { my_print('orange','Geo::IP',"Country look-up for an IP address"); } if ( $conf{'default_backend'} eq 'GD' ) { if ( eval( 'require GD' ) ) { my_print('green','GD',"PNG Image generation"); } else { my_print('orange','GD',"PNG Image generation"); } if ( eval( 'require GD::Text' ) ) { my_print('green',' + GD::Text',"Text inside PNG generated images"); } else { my_print('orange',' + GD::Text',"Text inside PNG generated images"); } if ( eval( 'require GD::Graph' ) ) { my_print('green',' + GD::Graph',"2D Graph generator"); } else { my_print('orange',' + GD::Graph',"2D Graph generator"); } if ( eval( 'require GD::Graph3d' ) ) { my_print('green','  + GD::Graph3d',"3D Graph generator"); } else { my_print('orange','  + GD::Graph3d',"3D Graph generator"); } } if ( $conf{'default_backend'} eq 'PS' ) { if ( -f $conf{'gs_path'} ) { my_print('green',"Ghostscript","Ghostscript (postscript generation tool) has been found"); } else { my_print('red',"Ghostscript","Ghostscript (postscript generation tool) has not been found in $conf{'gs_path'}"); } if ( eval( 'require PDF::API2' ) ) { my_print('green',"PDF::API2","PDF::API2 (PDF report generation) has been found"); } else { my_print('orange',"PDF::API2","PDF::API2 (PDF report generation) has not been found"); } } } # Write permissions : sub test_write_permissions($) { my $path = shift; local *TEMP; if ( open( TEMP, '>'.$path.'/generated/_tempfile' ) ) { my_print('green','generated/ directory perms',"generated/ sub-dir is writable by this webserver"); close( TEMP ); unlink $path.'/generated/_tempfile'; } else { my_print('red','generated/ directory perms',"generated/ sub-dir is not writable by this webserver : $! . Do chown -R apacheuser.apachegrp generated/"); } if ( open( TEMP, $path.'/Profiles/admin.user' ) ) { my_print('green','Profiles/ directory perms',"Profiles/ sub-dir is readable by this webserver"); close( TEMP ); } else { my_print('red','Profiles/ directory perms',"Profiles/ sub-dir is not readable by this webserver : $! . Do chown -R apacheuser.apachegrp Profiles/"); } } sub test_db_access() { if ( my $dbh = DB_Open() ) { my_print('green','DB access configuration','this script could have access to prelude DB'); } else { my $db_mysql=eval('require DBD::mysql'); my $db_pgsql=eval('require DBD::Pg'); if ($db_mysql or $db_pgsql) { my_print('red','DB access configuration','this script could have not access to prelude DB (might be a Functions/config.pl misconfiguration)'); } else { my_print('red','DB access configuration','this script could have not access to prelude DB (that is normal, DBI or DBD is missing)'); } } } sub test_password_protection() { if ( $::ENV{'REMOTE_USER'} ) { my_print('green','password-protection','piwi directory is password protected. look at Docs/user_file_format.txt to create profiles with privilege separation'); } else { my_print('orange','password-protection','piwi directory is not password protected. look at Docs/user_file_format.txt and modify Profiles/guest.user accordingly'); } } 1; piwi/Functions/console.pl0000600000000000000000000000026710002540465015724 0ustar rootroot00000000000000sub error($) { my $Error = shift; print STDERR "\nERROR : $Error\n"; } sub debug($) { my $Error = shift; if ( $conf{'debug'} ) { print STDOUT "\nDEBUG : $Error\n"; } } 1; piwi/Functions/score.pl0000600000000000000000000000356210010515472015375 0ustar rootroot00000000000000sub Source_AlertNb($) { my $SourceIP = shift; my $Filter = Filter->new(); my $Crit1 = Criteria->new(); $Crit1->Table( 'Address' ); $Crit1->Field( 'parent_type' ); $Crit1->Operator( '=' ); $Crit1->Value( 'S' ); $Filter->add_Criteria( $Crit1 ); my $Crit2 = Criteria->new(); $Crit2->Table( 'Address' ); $Crit2->Field( 'address' ); $Crit2->Operator( '=' ); $Crit2->Value( $SourceIP ); $Filter->add_Criteria( $Crit2 ); $Filter->Formula('A AND B'); $Filter->get_SQL(); my $Statement_NL = $Filter->SQL_EltNb(); my $Sth = $dbh->prepare( $Statement_NL ); $Sth->execute(); my $Count = $Sth->fetchrow_array(); $Sth->finish(); return $Count; } sub Source_AlertTypeNb($) { my $SourceIP=shift; my $SQL='SELECT count(DISTINCT Prelude_Classification.name) FROM Prelude_Classification,Prelude_Address WHERE '; $SQL.='Prelude_Classification.alert_ident=Prelude_Address.Alert_ident AND '; $SQL.="((Prelude_Address.parent_type='S') AND (Prelude_Address.address=?));"; my $Sth=$dbh->prepare($SQL); $Sth->execute($SourceIP); my $Count=$Sth->fetchrow_array(); $Sth->finish(); return $Count; } sub Source_TargetNb($) { my $SourceIP = shift; my %Target; my $SQL = 'SELECT DISTINCT Prelude_Address.alert_ident FROM Prelude_Address WHERE '; $SQL .= "((Prelude_Address.parent_type='S') AND (Prelude_Address.address=?));"; my $Sth = $dbh->prepare( $SQL ); $Sth->execute( $SourceIP ); while( my $AlertId = $Sth->fetchrow_array() ) { my $SQL = 'SELECT DISTINCT Prelude_Address.address FROM Prelude_Address WHERE '; $SQL .= "Prelude_Address.parent_type='T' AND Prelude_Address.alert_ident=?;"; my $Sth = $dbh->prepare( $SQL ); $Sth->execute( $AlertId ); if ( $Sth->rows() ) { my $Target = $Sth->fetchrow_array(); $Target{$Target} = 1; } $Sth->finish(); } $Sth->finish(); my @Target = keys %Target; my $Count = $#Target + 1; return $Count; } 1; piwi/Functions/nessus.pl0000600000000000000000000001432410003102373015572 0ustar rootroot00000000000000sub parse_nessus_nsr_file($$$) { my $nsr_file = shift; # .NSR file full path my $callback = shift; # function to call for each line my $callback_data = shift; # data to pass to this function if ( -f $nsr_file ) { # 2 sections in a NSR file : nessus configuration then scan results : my $in_DATA = 0; local *NSR; open( NSR, $nsr_file ) || die( "Can't open this nessus report : $!\n" ); while( my $line = ) { # Remove EOL : $line =~ s/\r|\n//g; # If we are in the second part of the file : if ( $in_DATA ) { # www.leroutier.net|www (80/tcp)|10107|INFO|... my ( $host, $service_port_protocol, $nessus_id, $type, $text ) = split( /\|/, $line, 5 ); if ( $nessus_id and $type and $text ) { # Handle INFO, REPORT or both : if ( $callback_data->{'nessus_allowed_types'}->{ $type } ) { my ( $service, $port, $protocol ) = ( $service_port_protocol =~ m/^([^\s]+)\s+\((\d+)\/(.*)\)$/ ); # host could be either IP address or hostname : my $ip = ''; $host =~ s/\s//g; if ( $host =~ m/[a-z]/i ) { my $iaddr = gethostbyname( $host ); if ( ! $iaddr ) {print "Can't resolve hostname '$Host'\n";exit();}; $ip = inet_ntoa( $iaddr ); } else { $ip = $host; } # In .nsr files, ';' means EOL : $text =~ s/;/LINE_SEP/g; &{ $callback }( $callback_data, [ $ip, $port, $protocol, $type, $nessus_id, $text ] ); } } } else { if ( $line =~ m/^\$DATA\$/ ) {$in_DATA = 1;}; } } } else { print "NSR report not found : $nsr_file\n"; return 0; } return 1; } sub add_nessus_entry_to_zone_port_list($$) { my $data_ref = shift; my $report_line = shift; my ( $ip, $port, $protocol, $type, $nessus_id, $text ) = @{ $report_line }; # my $line_zone = ''; foreach my $zone ( sort keys %{ $data_ref->{'network_zone_list'} } ) { if ( $ip =~ m/^$zone/ ) { $line_zone = $zone; }; } # Create empty structure at first use : if ( ! exists( $data_ref->{'nessus_port_list'}->{$line_zone} ) ) { $data_ref->{'nessus_port_list'}->{$line_zone} = { 'udp' => {}, 'tcp' => {} }; } if ( ! exists( $data_ref->{'nessus_port_list'}->{$line_zone}->{$protocol}->{$port} ) ) { $data_ref->{'nessus_port_list'}->{$line_zone}->{$protocol}->{$port} = { 'additional_data' => [], 'filter' => '' }; } # Add data to the port list : push @{ $data_ref->{'nessus_port_list'}->{$line_zone}->{$protocol}->{$port}->{'additional_data'} }, { 'type' => $type, 'nessus_id' => $nessus_id, 'text' => $text }; if ( ! $line_zone ) { print "This host ($ip) does not match any defined zone, please fix this !!\n"; } } sub add_nessus_entry_to_host_port_list($$) { my $data_ref = shift; my $report_line = shift; my ( $ip, $port, $protocol, $type, $nessus_id, $text ) = @{ $report_line }; # Create empty structure at first use : if ( ! exists( $data_ref->{'nessus_port_list'}->{$ip} ) ) { $data_ref->{'nessus_port_list'}->{$ip} = { 'udp' => {}, 'tcp' => {} }; } if ( ! exists( $data_ref->{'nessus_port_list'}->{$ip}->{$protocol}->{$port} ) ) { $data_ref->{'nessus_port_list'}->{$ip}->{$protocol}->{$port} = { 'additional_data' => [], 'filter' => '' }; } # Add data to the port list : push @{ $data_ref->{'nessus_port_list'}->{$ip}->{$protocol}->{$port}->{'additional_data'} }, { 'type' => $type, 'nessus_id' => $nessus_id, 'text' => $text }; } sub create_filter_from_port_list($$$$) { my $port_list = shift; my $match_type = shift; my $callback = shift; my $callback_data = shift; if ( $match_type eq 'ip' ) { $operator = '='; }; if ( $match_type eq 'zone' ) { $operator = 'S'; }; foreach my $ip ( sort keys %{ $port_list } ) { if ( exists( $callback_data->{'callback_list'}->{'foreach_ip'} ) ) { &{ $callback_data->{'callback_list'}->{'foreach_ip'} }( $callback_data, $ip ); } my $Crit1 = Criteria->new(); $Crit1->Table( 'Address' ); $Crit1->Field( 'address' ); $Crit1->Operator( $operator ); $Crit1->Value( $ip ); my $Crit1b = Criteria->new(); $Crit1b->Table( 'Address' ); $Crit1b->Field( 'parent_type' ); $Crit1b->Operator( '=' ); $Crit1b->Value( 'T' ); foreach my $protocol ( keys %{ $port_list->{$ip} } ) { if ( exists( $callback_data->{'callback_list'}->{'foreach_protocol'} ) ) { &{ $callback_data->{'callback_list'}->{'foreach_protocol'} }( $callback_data, $ip, $protocol ); } my $Crit2 = Criteria->new(); $Crit2->Table( 'Service' ); $Crit2->Field( 'protocol' ); $Crit2->Operator( '=' ); $Crit2->Value( $protocol ); my $Crit2b = Criteria->new(); $Crit2b->Table( 'Service' ); $Crit2b->Field( 'parent_type' ); $Crit2b->Operator( '=' ); $Crit2b->Value( 'T' ); foreach my $port ( sort {$a <=> $b} keys %{ $port_list->{$ip}->{$protocol} } ) { if ( exists( $callback_data->{'callback_list'}->{'foreach_port'} ) ) { &{ $callback_data->{'callback_list'}->{'foreach_port'} }( $callback_data, $ip, $protocol, $port ); } my $Crit3 = Criteria->new(); $Crit3->Table( 'Service' ); $Crit3->Field( 'port' ); $Crit3->Operator( '=' ); $Crit3->Value( $port ); # Create an empty Filter : my $Filter = Filter->new(); # Add the 3 criteria to the filter : $Filter->Formula( 'A AND B AND C AND D AND E' ); $Filter->add_Criteria ( $Crit1 ); $Filter->add_Criteria ( $Crit1b ); $Filter->add_Criteria ( $Crit2 ); $Filter->add_Criteria ( $Crit2b ); $Filter->add_Criteria ( $Crit3 ); if ( $callback_data->{'filter_directory'} ) { # Set filter file name : $Filter->FileName( ( $callback_data->{'filter_directory'} )."/nessus-$ip-$protocol-$port.flt" ); } # Set filter comment : my @additional_data = (); foreach my $hash_ref ( @{ $port_list->{$ip}->{$protocol}->{$port}->{'additional_data'} } ) { push @additional_data, join( 'ELT_SEP', ( $hash_ref->{'type'}, $hash_ref->{'nessus_id'}, $hash_ref->{'text'} ) ); } $Filter->comment( join( 'SECTION_SEP', @additional_data ) ); # Associate new filter to its origin port : $port_list->{$ip}->{$protocol}->{$port}->{'filter'} = $Filter; # Process this new filter : &{ $callback }( $callback_data, $Filter ); } } } } 1; piwi/Functions/DateTime.pl0000600000000000000000000000057607767652667016021 0ustar rootroot00000000000000sub GMT_to_LocalTime($) { my $GMT = shift; if ( $conf{'GMTdiff'} ) { my @Elements = ( $GMT =~ m/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/ ); @Elements = Date::Calc::Add_Delta_YMDHMS( @Elements, 0, 0, 0, $conf{'GMTdiff'}, 0, 0 ); $GMT = sprintf( "%04d-%02d-%02d ", @Elements[0,1,2] ); $GMT .= sprintf( "%02d:%02d:%02d", @Elements[3,4,5] ); } return $GMT; } 1; piwi/Functions/FakeFunctions.pl0000600000000000000000000000020707772601715017033 0ustar rootroot00000000000000sub FilterEdit_Link() { print ' '; } sub Statistics_Link() { print "Statistics"; } 1; piwi/Functions/pie.pl0000600000000000000000000000135607732402714015051 0ustar rootroot00000000000000sub piechart(\@$$) { my $DataRef=shift; my $Label=shift; my $FileName=shift; my $graph=GD::Graph::pie->new(450,300); if ($graph->can_do_ttf()) { $graph->set( label => $Label, transparent => $conf{'GD_transparent'}, interlaced => 1, suppress_angle => 9 ); my $gd=$graph->plot($DataRef); local *PNG; undef $!; open(PNG,'>'.$FileName); if ($! and ($! !~ m/Inappropriate ioctl for device/i)) { &error("Can't write image $FileName : did you do the chown -R like told in Docs/INSTALL.txt ? ($!)"); return 0; } print PNG $gd->png(); close(PNG); } else { &error('It seems your libgd librairy was not compiled with freetrype support.'); } } 1; piwi/Functions/web.pl0000600000000000000000000000025710003067263015037 0ustar rootroot00000000000000sub error($) { my $Error = shift; print STDOUT "
$Error
"; } sub debug($) { my $Error = shift; if ( $conf{'debug'} ) {error( $Error );}; } 1; piwi/Functions/Sensor_Tree.pl0000600000000000000000000001505310003102373016502 0ustar rootroot00000000000000sub sensor_tree() { my $Path = $cgi->param( 'path' ); if ( ! $Path ) { $Path = '/'; }; my @Path = split( /\//, $Path ); for( my $i=1 ; $i<4 ; $i++ ) { if ( ! $Path[$i] ) { $Path[$i] = ''; }; } # VLAN list : my @vlan = (); my $sql = 'SELECT analyzerid FROM Prelude_Analyzer WHERE '; $sql .= "parent_type='H' GROUP BY analyzerid;"; my $sth = $dbh->prepare( $sql ); $sth->execute(); while( my $AnalyzerId = $sth->fetchrow_array() ) { my $sql = 'SELECT * FROM Prelude_Analyzer WHERE '; $sql .= "parent_type='H' AND analyzerid=? ORDER BY "; $sql .= 'parent_ident DESC LIMIT 1;'; my $sth = $dbh->prepare( $sql ); $sth->execute( $AnalyzerId ); my $Analyzer = $sth->fetchrow_hashref(); $sth->finish(); $sql = 'SELECT * FROM Prelude_Node WHERE '; $sql .= "parent_type='H' AND alert_ident=?;"; $sth = $dbh->prepare( $sql ); $sth->execute( $Analyzer->{'parent_ident'} ); my $Node = $sth->fetchrow_hashref(); $sth->finish(); $sql = 'SELECT * FROM Prelude_Address WHERE '; $sql .= "parent_type='H' AND alert_ident=?;"; $sth = $dbh->prepare( $sql ); $sth->execute( $Analyzer->{'parent_ident'} ); if ( $sth->rows() ) { while ( my $Address = $sth->fetchrow_hashref() ) { tree_add( \@vlan, $Address, $Analyzer, $Node, $Analyzer->{'analyzerid'} ); } } else { # no Address object for this sensor : my $Address = {}; tree_add( \@vlan, $Address, $Analyzer, $Node, $Analyzer->{'analyzerid'} ); } $sth->finish(); } $sth->finish(); ################################################################ my @last = (); my $lpath = '/'; my $Output = cool( '+', \@last,1,'' ).' '; $Output .= "ALL
\n"; for( my $i = 0 ; $i <= $#vlan ; $i ++ ) { if ( $vlan[$i] ) { if ( $i eq $#vlan ) {$last[0] = 1;} else {$last[0] = 0;}; if ( $Path[1] ne $i ) {$lpath = '/'.$i;}; $Output .= cool( '\\+', \@last, ( $Path[1] eq $i ), $lpath ); $Output .= " $i - "; $Output .= make_filter( 'Analyzer.vlan_num', $i, $vlan[$i]->{'name'} ); $Output .= "
\n"; if ( $Path[1] eq $i ) { $lpath = '/'.$i.'/'; my @addr_lst = sort keys %{$vlan[$i]->{'addr_lst'}}; my $cnt = 0; foreach my $addr ( @addr_lst ) { if ( $cnt eq $#addr_lst ) {$last[1] = 1;} else {$last[1] = 0;}; $cnt ++; if ( $Path[2] ne $addr ) {$lpath = '/'.$i.'/'.$addr;}; $Output .= cool( '|\\+', \@last,( $Path[2] eq $addr ), $lpath ); $Output .= ' '; $Output .= make_filter( 'Analyzer.address', $addr, $addr ); $Output .= "
\n"; if ( $Path[2] eq $addr ) { $lpath = '/'.$i.'/'.$addr.'/'; my @a_id_lst = sort keys %{$vlan[$i]->{'addr_lst'}->{$addr}}; my $cnt2 = 0; foreach my $a_id ( @a_id_lst ) { if ( $cnt2 eq $#a_id_lst ) {$last[2] = 1;} else {$last[2] = 0;}; $cnt2 ++; if ( $Path[3] ne $a_id ) {$lpath = '/'.$i.'/'.$addr.'/'.$a_id;}; $Output .= cool( '||\\+', \@last, ( $Path[3] eq $a_id ), $lpath ); $Output .= ' '; $Output .= make_filter( 'Analyzer.analyzerid', $a_id, $a_id ); $Output .= "
\n"; if ( $Path[3] eq $a_id ) { $lpath = '/'.$i.'/'.$addr.'/'.$a_id; my @keys = sort keys %{$vlan[$i]->{'addr_lst'}->{$addr}->{$a_id}}; my $cnt3 = 0; foreach my $key ( @keys ) { if ( $cnt3 eq $#keys ) { $last[3] = 1; } else { $last[3] = 0; } $cnt3 ++; $Output .= cool( '|||\\]', \@last,0,'' )." $key = "; my $label = $vlan[$i]->{'addr_lst'}->{$addr}->{$a_id}->{$key}; if ( $key ne 'Location' ) { $label = make_filter( 'Analyzer.'.lc( $key ), $label, $label ); } $Output .= $label; $Output .= "
\n"; } } } } } } } } return $Output; } sub tree_add($$$$$) { my $vlan = shift; my $Address = shift; my $Analyzer = shift; my $Node = shift; my $AnalyzerId = shift; my $Model = $Analyzer->{'model'}; $Model =~ s/Log Monitoring Lackey/LML/; $Model =~ s/\s/ /g; my $Class = $Analyzer->{'class'}; $Class =~ s/^Network /N/; $Class =~ s/^Host based /H/; $Class =~ s/Intrusion Detection System$/IDS/; my $Location = ( ( ! $Node->{'location'} )?( $Node->{'name'} ):( $Node->{'location'} ) ) || ' '; if ( ! $Location) {$Location = 'n/a';}; my $address = $Address->{'address'}; # my $category = $Address->{'category'}; # my $netmask = $Address->{'netmask'}; my $vlan_num = $Address->{'vlan_num'}; my $vlan_name = $Address->{'vlan_name'}; ################################################################## if ( ! $vlan_num ) {$vlan_num = 0;}; if ( ! $vlan_name ) {$vlan_name = 'noname';}; if ( ! $address ) {$address = 'noaddress';}; if ( ! $vlan->[$vlan_num] ) { $vlan->[$vlan_num]={ 'name' => 'noname', 'addr_lst' => {} } } $vlan->[$vlan_num]->{'name'} = $vlan_name; ################################################################## if ( ! $vlan->[$vlan_num]->{'addr_lst'}->{$address} ) { $vlan->[$vlan_num]->{'addr_lst'}->{$address} = {}; } if ( ! $vlan->[$vlan_num]->{'addr_lst'}->{$address}->{$AnalyzerId} ) { $vlan->[$vlan_num]->{'addr_lst'}->{$address}->{$AnalyzerId} = { 'Class' => $Class, 'Model' => $Model, 'Location' => $Location } } } sub cool($$$$) { my $string = shift; my $last = shift; my $opened = shift; my $link = shift; my $result = ''; for( my $i = 0 ; $i < length( $string ) ; $i ++ ) { if ( $last->[$i] ) { if ( substr( $string, $i, 1 ) eq '|' ) {$result .= tree_image( 'empty10' );}; if ( substr( $string, $i, 1 ) eq '\\' ) {$result .= tree_image( 'inter10' );}; } else { if ( substr( $string, $i, 1 ) eq '|' ) {$result .= tree_image( 'empty00' );}; if ( substr( $string, $i, 1 ) eq '\\' ) {$result .= tree_image( 'inter00' );}; } } if ( $string =~ m/\]$/ ) {$result .= tree_image( 'leaf10' );}; if ( $string =~ m/\+$/ ) { if ( $link ) {$result .= "";}; if ( $opened ) { $result .= tree_image( 'leaf01' ); } else { $result .= tree_image( 'leaf00' ); } if ( $link ) {$result .= '';}; } return $result; } sub tree_image($) { my $image = shift; return ""; } sub make_filter($$$) { my $file = shift; my $value = shift; my $label = shift; my $link = "$label"; return $link; } 1; piwi/Functions/_AlertDetails_XML.pl0000600000000000000000000000242607772177247017545 0ustar rootroot00000000000000sub ShowValues(\@) { my $ArrayRef = shift; my $Output = ''; my @Path = @{$ArrayRef}; my $Path = join( '/', @Path ); my $Indent = $#Path + 1; my @Results; if ( $Path eq 'Alert' ) { @Results = ( 1, 1, 'ident', $AlertId ); } else { @Results = get_Data( $Path, $AlertId, 'ALL' ); } if ( $Results[0] ) { my ( $LastTable ) = ( $Path =~ m/([A-Z]+)$/i ); foreach my $LineNb ( 1..$Results[0] ) { my %Results = get_DataLine( \@Results, $LineNb ); foreach my $Key ( keys %Results ) { if ( ! $Exclude{$Key} ) { my $Link = 'Filters'.$conf{'extension'}.'?mode=edit&'; $Link .= 'Table_A='.$LastTable; $Link .= '&Field_A='.$Key.'&Operator_A='.url_encode('=').'&'; $Link .= 'Value_A='.url_encode($Results{$Key}); $Output .= '  'x$Indent; $Output .= "<$Key>"; $Results{$Key} =~ s//>/g; if ( $Results{$Key} =~ m/\n/ ) { $Results{$Key} = '
'.$Results{$Key}.'
'; $Results{$Key} =~ s/\n+$//g; $Results{$Key} =~ s/\n/
/g; } $Output .= $Results{$Key}; $Output .= "</$Key>"; $Output .= "
\n"; $Output .= ""; } } } } return ( $Results[0], $Output ); } 1; piwi/Functions/packet.pl0000600000000000000000000002670707711213161015543 0ustar rootroot00000000000000sub Packet_Ethernet($$) { my $Sdata=shift; my $Output_Type=shift; my $Output="
$Sdata

\n"; if ($Output_Type eq 'STD') { if ($conf{'ettercap_mac_db'} and -f $conf{'ettercap_mac_db'}) { my ($MAC_S,$MAC_T,$ETH_TYPE_L,$ETH_TYPE_N)=($Sdata =~ m/^(\S+) -> (\S+) \[ether_type=(\S+) \((\d+)\)\]$/); $MAC_S=get_Vendor_from_MAC_Address($MAC_S); $MAC_T=get_Vendor_from_MAC_Address($MAC_T); $Output.="Source : $MAC_S
\n"; $Output.="Target : $MAC_T
\n"; $Output.="Upper Layer (3/Transport) Protocol : $ETH_TYPE_N ($ETH_TYPE_L)"; } else { &error("ettercap MAC vendor DB not found : $conf{'ettercap_mac_db'}"); } } return $Output; } sub get_Vendor_from_MAC_Address($) { my $MAC=shift; my @Elements=split(/:/,uc($MAC)); my $Vendor=sprintf("%02s:%02s:%02s",@Elements[0..2]); my $ID=sprintf("%02s:%02s:%02s",@Elements[3..5]); if (($Vendor eq $ID) and ($Vendor eq 'FF:FF:FF')) { return 'Broadcast'; } else { local *MAC_VENDOR_DB; undef $!; open(MAC_VENDOR_DB,$conf{'ettercap_mac_db'}); if ($! and ($! !~ m/Inappropriate ioctl for device/i)) { &error("Error opening ettercap mac-fingerprints DB : $!"); } else { my $found=0; while(!$found and (my $line=)) { if ($line =~ m/^$Vendor\s+(.*)$/) { $Vendor=$1.' ('.$Vendor.')'; $Vendor =~ s/\r|\n//g; $found=1; } } } close(MAC_VENDOR_DB); return "$Vendor-$ID"; } } sub Packet_ARP($$) { my $Sdata=shift; my $Output_Type=shift; my $Output=''; # STD : if ($Output_Type eq 'STD') { $Output=<<"EOB";
$Sdata

EOB } return $Output; } sub Packet_IPv4($$) { my $Sdata=shift; my $Output_Type=shift; # source addr | dest addr | Ver | Hdr Len | TOS | length | ID | flags | offset | TTL | chksum || Options # 61.104.179.100 -> 81.91.66.90 [hl=20,version=4,tos=0,len=34,id=27096,ttl=113,prot=17,frag=[offset=64]] my $Output=''; if ($Sdata =~ m/^([\d\.]+)\s+\-\>\s+([\d\.]+)\s+\[(.+)\]$/) { my ($Src_IP,$Tgt_IP,$Others)=($1,$2,$3); my %Others; foreach my $Key (split(/,/,$Others)) { my ($K,$V)=split(/=/,$Key,2); $Others{$K}=$V; } if (!defined($Others{'frag'})) {$Others{'frag'}='[offset=]';}; $Others{'frag'} =~ s/\[|\]|\s//g; my %Frag; foreach my $Key (split(/,/,$Others{'frag'})) { my ($K,$V)=split(/=/,$Key,2); if ($K eq 'DF') {$V='X';}; $Frag{$K}=$V; } my %TOS; $TOS{'DS'}=(int($Others{'tos'}) & 252)/4; $TOS{'ECT'}=(int($Others{'tos'}) & 2)/2; $TOS{'CE'}=(int($Others{'tos'}) & 1); # STD : if ($Output_Type eq 'STD') { $Output=<<"EOB";
$Sdata

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
IP Version=$Others{'version'} Hdr.Length=$Others{'hl'} TOS=$Others{'tos'} Total Length=$Others{'len'}
DS=$TOS{'DS'} ECT=$TOS{'ECT'} CE=$TOS{'CE'}
Identification=$Others{'id'} - DF MF Fragment Offset=$Frag{'offset'}
$Frag{'DF'}  
Time To Live=$Others{'ttl'} Protocol Number=$Others{'prot'} Header Checksum
32 bit Source Address=$Src_IP
32 bit Destination Address=$Tgt_IP
Options (0 to 10 Words of 32 Bits)
EOB } } return $Output; } sub Packet_TCP($$) { my $Sdata=shift; my $Output_Type=shift; # 35404 -> 80 [flags=PUSH ACK ,seq=980682701,ack=1555759336,win=39760] # src prt | dst prt | R1 | R0 | URG | ACK | PSH | RST | SYN | FIN | seq | ack | offset | res | window | urp | CRC || options my $Output=''; if ($Sdata =~ m/(\d+)\s->\s(\d+)\s+\[(.*)\]/) { my ($Src_P,$Tgt_P,$Others)=($1,$2,$3); my @Temp=split(/,/,$Others); my %Others; foreach my $Key (@Temp) { my ($K,$V)=split(/=/,$Key); $V =~ s/\s+$//; $Others{$K}=$V; } my @Flags=split(/\s+/,$Others{'flags'}); my %Flags; foreach my $Flag (@Flags) { $Flags{$Flag}='X'; } # STD : if ($Output_Type eq 'STD') { $Output=<<"EOB";
$Sdata

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
Source Port=$Src_P Destination Port=$Tgt_P
Sequence Number=$Others{'seq'}
Acknowledgement Number=$Others{'ack'}
Data
Offset
- - - - C
W
R
E
C
M
E
U
R
G
A
C
K
P
U
S
H
R
S
T
S
Y
N
F
I
N
Window=$Others{'win'}
$Flags{'CWR'} $Flags{'ECME'} $Flags{'URG'} $Flags{'ACK'} $Flags{'PUSH'} $Flags{'RST'} $Flags{'SYN'} $Flags{'FIN'}
Checksum Urgent Pointer=$Others{'urg'}
Options (0 to 10 Words of 32 Bits)
EOB } } return $Output; } sub Packet_UDP($$) { my $Sdata=shift; my $Output_Type=shift; my $Output=''; if ($Sdata =~ m/(\d+)\s->\s(\d+)\s+\[(.*)\]/) { my ($Src_P,$Tgt_P,$Others)=($1,$2,$3); my @Temp=split(/,/,$Others); my %Others; foreach my $Key (@Temp) { my ($K,$V)=split(/=/,$Key); $V =~ s/\s+$//; $Others{$K}=$V; } # STD : if ($Output_Type eq 'STD') { $Output=<<"EOB";
$Sdata

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
Source Port=$Src_P Destination Port=$Tgt_P
Total Length=$Others{'len'} Checksum (optional)
EOB } } return $Output; } sub Packet_ICMP($$) { my $Sdata=shift; my $Output_Type=shift; my $Output="
$Sdata

\n"; return $Output; } 1; piwi/Functions/_Filters.pl0000600000000000000000000001423310003102373016020 0ustar rootroot00000000000000sub CreateLink() { my $Link = ''; foreach my $Key ( $cgi->param() ) { $Link .= $Key.'='.url_encode( $cgi->param( $Key ) ).'&'; } return $Link; } sub PageNav_Init() { # By default, display 'by_page' alerts per page, # starting from the first page, in reverse order : if ( ! defined( $cgi->param( 'page_num' ) ) ) {$cgi->param( 'page_num', 0 );}; $cgi->param( 'page_num', int( $cgi->param( 'page_num' ) ) ); if ( ( ! $cgi->param( 'by_page' ) ) || ($cgi->param( 'by_page' ) !~ m/^\d+$/) ) { $cgi->param( 'by_page', $conf{'nb_resbypage'} ); } else { $cgi->param( 'by_page', int( $cgi->param( 'by_page' ) ) || $conf{'nb_resbypage'} ); } if ( ! defined( $cgi->param( 'desc' ) ) ) {$cgi->param( 'desc', '' );}; } sub AlertList($) { my $Filter = shift; my $Statement_L = $Filter->SQL_EltList(); debug( "Res: $Statement_L" ); my $Sth = $dbh->prepare( $Statement_L ); LIMIT_values( $Sth, $cgi->param( 'by_page' ), $cgi->param( 'page_num' )*$cgi->param( 'by_page' ) ); $Sth->execute() || debug( 'SQL Error : '.$dbh->errstr ); my %KeyDisplayed = (); my %KeyOutput = (); my $AlertDisplayedNb = 0; my @DisplayList = (); while( our $AlertId = $Sth->fetchrow_array() ) { our %Cache = (); local *TEMP; open( TEMP, '>generated/tmp_'.$ENV{'REMOTE_ADDR'} ) || debug( 'ERROR : '.$! ); select( TEMP ); ParseComponent( 'AlertList_Body' ); select( STDOUT ); close( TEMP ); open( TEMP, ' ) { if ( $KeyOutput{$AlertId} ) { $KeyOutput{$AlertId} .= $Line; } else { $KeyOutput{$AlertId} = $Line; } } close( TEMP ); push @DisplayList, $AlertId; $AlertDisplayedNb ++; } $Sth->finish(); my $DisplayCnt = 0; if ( $cgi->param( 'sortby' ) eq 'groupkey' ) { @DisplayList = sort @DisplayList; } my @Styles = ( 'odd', 'even' ); foreach my $AlertKey ( @DisplayList ) { if ( $DisplayCnt < $cgi->param( 'by_page' ) ) { my $Style = " class=\"".( $Styles[$DisplayCnt % ( $#Styles + 1 ) ] )."\""; $KeyOutput{$AlertKey} =~ s/STYLE_HERE/$Style/mg; print $KeyOutput{$AlertKey}; $DisplayCnt ++; } } unlink( 'generated/tmp_'.$ENV{'REMOTE_ADDR'} ); } ########################################################################### sub FilterEdit_Link() { if ( $cgi->param( 'mode' ) ne 'edit' ) { if ( $cgi->param( 'load' ) ) { print "param( 'load' ) ); foreach my $Key ( $cgi->param() ) { if ( $Key =~ m/^val([A-Z])$/ ) { my $val = $1; print '&val'.$val.'='.url_encode( $cgi->param( 'val'.$val ) ); } } print "\" target=_top>Edit current filter"; return 1; } } print 'Edit current filter'; return 0; } sub Statistics_Link() { if ( $cgi->param( 'mode' ) ne 'edit' ) { if ( $cgi->param( 'load' ) ) { if ( $cgi->param( 'load' ) !~ m/^defaults\// ) { print "param( 'load' ) ); print "\" target=_top>Statistics"; return 1; } } } print 'Statistics'; return 0; } ########################################################################### sub ValueInput($) { my $Index = shift; print "param( 'Value_'.$Index )."\">\n"; } sub TableList($) { my $Index = shift; print "\n"; print "param( 'Field_'.$Index ) )."\">\n"; } sub OperatorList($) { my $Index = shift; my %OpList = (); (%OpList) = (%OpList,'=','equals to'); (%OpList) = (%OpList,'!=','differs from'); (%OpList) = (%OpList,'>','is greater than'); (%OpList) = (%OpList,'<','is lower than'); (%OpList) = (%OpList,'>=','is greater or equal'); (%OpList) = (%OpList,'<=','is lower or equal'); (%OpList) = (%OpList,'S','starts with'); (%OpList) = (%OpList,'C','contains'); (%OpList) = (%OpList,'E','ends with'); (%OpList) = (%OpList,'M','matches (% as wildcard)'); print "\n"; } sub GroupBy($) { my $crit = shift; if ( $cgi->param( 'groupby' ) =~ m/$crit/ ) {print ' selected';}; } sub Page_Navigation($$$$) { my $Current_Page_Num = shift; my $ResNb_by_Page = shift; my $TotalResultNb = shift; my $Show_ResNb = shift; my $PageNb = $TotalResultNb / $ResNb_by_Page; if ( $PageNb ne int( $PageNb ) ) {$PageNb = int( $PageNb ) + 1;}; print "
"; if ( $Show_ResNb ) { print "$TotalResultNb results for those filters."; print " Page ".( $Current_Page_Num + 1 )."/$PageNb."; } if ( $TotalResultNb >= $ResNb_by_Page ) { print ""; my %done; foreach my $i ( 0, ( $Current_Page_Num - 1 ), ( $Current_Page_Num + 1 ), $PageNb - 1 ) { if ( ! exists( $done{$i} ) ) { # Set this for CreateLink : $cgi->param( 'page_num', $i ); my ( $Link_Start, $Link_End ) = ( '', '' ); if ( ( $i ne $Current_Page_Num ) and ( $i >= 0 ) and ( $i < $PageNb ) ) { $Link_Start = ""; $Link_End = ''; } # my @List = (); if ( $i eq 0 ) {push @List, 'First';}; if ( $i eq ( $Current_Page_Num - 1 ) ) {push @List, 'Prev';}; if ( $i eq ( $Current_Page_Num + 1 ) ) {push @List, 'Next';}; if ( $i eq ( $PageNb - 1 ) ) {push @List, 'Last';}; foreach my $elt ( @List ) { print ''; } $done{$i} = 1; } } print '
'; print $Link_Start; print $elt; print $Link_End; print '
'; # Restore initial value : $cgi->param( 'page_num', $Current_Page_Num ); } print '

'; } 1; piwi/Functions/_HeartBeat.pl0000600000000000000000000000027607772165300016273 0ustar rootroot00000000000000sub convert_s2hms($) { my $s = shift; my $h = int( $s / 3600 ); my $m = int( ( $s - $h*3600 ) / 60 ); $s = $s - $m*60 - $h*3600; return sprintf( "%02d:%02d:%02d", $h, $m, $s ); } 1; piwi/Functions/_AlertDetails.pl0000600000000000000000000001030110010535701016760 0ustar rootroot00000000000000sub packet_payload__binary2mixed($) { my $binary = shift; my $output = "
";

	while( $binary )
	{
		my $bin_line;
		if ( length( $binary ) <= 16 )
		{
			$bin_line = $binary;
			$binary = '';
		}
		else
		{
			$bin_line = substr( $binary, 0, 16 );
			$binary = substr( $binary, 16, length( $binary ) - 16 );
		}

		my $hex_line = '';
		my $ascii_line = '';
		for( my $i = 0; $i < length( $bin_line ) ; $i ++ )
		{
			my $char = substr( $bin_line, $i, 1 );
			$hex_line .= sprintf( "%02X " , ord( $char ) );
			if ( $i and ! ( ( $i + 1 ) % 4 ) ) { $hex_line .=' '; };

			if ( ( ord( $char ) < 32 ) or ( ord( $char ) > 127 ) ) { $char = '.'; };

			$ascii_line .= $char;
		}
		for( my $i = length( $bin_line ) ; $i < 16 ; $i ++ )
		{
			$hex_line .= '.. ';
			if ( $i and ! ( ( $i + 1 ) % 4 ) ) { $hex_line .=' '; };
		}

		$output .= "$hex_line | $ascii_line\n";
	}

	$output .= "
"; return $output; } sub packet_payload__ascii_only($) { my $binary = shift; my $output = ''; for( my $i = 0; $i < length( $binary ) ; $i ++ ) { my $char = substr( $binary, $i, 1 ); my $ord = ord( $char ); if ( ( ( $ord >= 32 ) and ( $ord <= 127 ) ) or ( $char =~ m/\r|\n/ ) ) { $output .= $char; } else { $output .= '.'; } } $output =~ s/(.{80})/$1 <=\n/g; $output =~ s//>/; $output = "
$output
"; return $output; } sub AlertDetail_Transform_Add_data($$) { my $meaning = shift; my $data = shift; if ( $meaning ne 'Payload Hexadecimal Dump' ) { if ( $meaning ne 'Packet Payload' ) { if ( ( $meaning eq 'Passive OS Fingerprint' ) and $conf{'ettercap_fp_db'} ) { if ( -f $conf{'ettercap_fp_db'} ) { $data = getosbyfingerprint( $data ); } else { error( "ettercap OS fingerprint DB not found : $conf{'ettercap_fp_db'}" ); } } else { if ( $meaning eq 'Ethernet header' ) { $data = ''.Packet_Ethernet( $data, 'STD' ).''; } else { $data =~ s/\n/
\n/g; } } AlertDetail_Display_Add_data( $meaning, $data ); } else { AlertDetail_Display_Add_data( $meaning.' - Hexadecimal Dump', packet_payload__binary2mixed( $data ) ); AlertDetail_Display_Add_data( $meaning.' - ASCII only Dump', packet_payload__ascii_only( $data ) ); } } else { $data =~ s//>/g; my $Mixed = "
\n
$data
"; my $ASCII = ''; foreach my $Line ( split( /\n/, $data ) ) { my $HEX = substr( $Line, 0, 50 ); foreach my $Byte ( split( /\s+/, $HEX ) ) { my $dec = hex( $Byte ); my $char = chr( $dec ); $char =~ s/\r//g; $char =~ s/\n/
/g; if ( $char and ( $char ne '
' ) and ( ( $dec < 32 ) or ( $dec > 127 ) ) ) { $char = '.'; } else { if ( $char ne '
' ) { $char =~ s//>/g; } } $ASCII .= $char; } } my $NewASCII = ''; foreach my $line ( split( /
/, $ASCII ) ) { $line =~ s/(.{80})/$1
/g; $NewASCII .= $line.'
'; } AlertDetail_Display_Add_data( 'Payload Hexadecimal Dump', $Mixed ); AlertDetail_Display_Add_data( 'Payload ASCII only Dump', $NewASCII ); } } sub AlertDetail_Display_Add_data($$) { my $meaning = shift; my $data = shift; my @styles = ( 'even', 'odd' ); my $skin = $styles[$cnt % 2]; print " "; print "$meaning"; print "$data"; print "\n"; $cnt ++; } sub getosbyfingerprint($) { my $OSfingerprint = shift; my $OSname = 'unknown OS fingerprint : '.$OSfingerprint; local *OS_FINGERPRINT_DB; undef $!; open( OS_FINGERPRINT_DB, $conf{'ettercap_fp_db'} ); if ( $! and ( $! !~ m/Inappropriate ioctl for device/i ) ) { error( "Error opening ettercap fingerprint DB : $!" ); return $OSfingerprint; } my $found = 0; while( ! $found and ( my $Line = ) ) { # 16D0:05B4:40:00:0:1:1:0:S:30:Mandrake 8.2 if ( $Line =~ m/^$OSfingerprint:(.*)[\r|\n]+$/i ) { $OSname = "$1 ($OSfingerprint)"; $found = 1; } } close( OS_FINGERPRINT_DB ); return $OSname } sub ExtURL($) { my $URL = shift; return "$URL"; } 1; piwi/Functions/_Stats.pl0000600000000000000000000000343510003102373015510 0ustar rootroot00000000000000sub TimePeriodType_List() { my %Types = (); %Types = (%Types, 'YYYY-MM-DD', 'Date' ); %Types = (%Types, 'YYYY-MM', 'Year+Month' ); %Types = (%Types, 'YYYY', 'Year' ); %Types = (%Types, 'MM', 'Month' ); %Types = (%Types, 'DD', 'Month Day' ); %Types = (%Types, 'HH', 'Hour' ); foreach my $Type ( 'YYYY-MM-DD', 'YYYY-MM', 'YYYY', 'MM', 'DD', 'HH' ) { my $checked = ''; if ( $Type eq $cgi->param( 'TimePeriodType' ) ) {$checked = ' checked';}; print " '; print $Types{$Type}.' ('.$Type.")
\n"; } } sub OutputType_List() { my @Types = (); if ( $cgi->param( 'backend' ) eq 'HTML' ) { @Types = ( @Types, 'text/html', 'HTML table' ); } if ( $cgi->param( 'backend' ) eq 'GD' ) { if ( ! defined( $miss{'GD::Graph'} ) ) {$miss{'GD::Graph'} = 0;}; if ( ! defined( $miss{'GD::Graph3d'} ) ) {$miss{'GD::Graph3d'} = 0;}; if ( ! $miss{'GD::Graph'} ) { @Types = ( @Types, 'png/pie', 'pie chart' ); @Types = ( @Types, 'png/lines', 'lines' ); @Types = ( @Types, 'png/area', 'areas' ); @Types = ( @Types, 'png/bars', 'vertical bars' ); @Types = ( @Types, 'png/hbars', 'horizontal bars' ); if (!$miss{'GD::Graph3d'}) { @Types = ( @Types, 'png/lines3d', '3d lines' ); @Types = ( @Types, 'png/bars3d', '3d vertical bars' ); } } } if ( $cgi->param( 'backend' ) eq 'PS' ) { @Types = ( @Types, 'png/pie', 'pie chart' ); @Types = ( @Types, 'png/bars', 'vertical bars' ); } if ( ! $cgi->param( 'OutputType' ) ) {$cgi->param( 'OutputType', $Types[0] );}; for( my $i = 0 ; $i <= ( $#Types / 2 ) ; $i ++ ) { my $selected = ''; if ( $Types[$i*2] eq $cgi->param( 'OutputType' )) {$selected = ' selected';}; print "