From 092c1e4a0d48de692db7a9a79c750cac85727981 Mon Sep 17 00:00:00 2001 From: allfro Date: Mon, 14 Jan 2013 16:52:29 -0500 Subject: [PATCH] Added support for automatic Canari package root detection. --- docs/Makefile | 153 ++++++++ docs/canari.rst | 452 +++++++++++++++++++++++ docs/conf.py | 246 ++++++++++++ docs/development.rst | 433 ++++++++++++++++++++++ docs/index.rst | 21 ++ docs/intro.rst | 134 +++++++ docs/make.bat | 190 ++++++++++ src/canari/commands/common.py | 58 ++- src/canari/commands/create_package.py | 12 +- src/canari/commands/create_transform.py | 9 +- src/canari/commands/debug_transform.py | 2 +- src/canari/commands/delete_transform.py | 8 +- src/canari/commands/generate_entities.py | 28 +- src/canari/commands/help.py | 1 + src/canari/commands/rename_transform.py | 8 +- src/canari/commands/run_server.py | 10 +- src/canari/commands/run_transform.py | 2 +- 17 files changed, 1726 insertions(+), 41 deletions(-) create mode 100644 docs/Makefile create mode 100644 docs/canari.rst create mode 100644 docs/conf.py create mode 100644 docs/development.rst create mode 100644 docs/index.rst create mode 100644 docs/intro.rst create mode 100644 docs/make.bat diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..7893ce4 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,153 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + -rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/sploitego.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/sploitego.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/sploitego" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/sploitego" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." diff --git a/docs/canari.rst b/docs/canari.rst new file mode 100644 index 0000000..87d83d8 --- /dev/null +++ b/docs/canari.rst @@ -0,0 +1,452 @@ +.. _ref_canari_commander: + +Canari Commander +================ + +The Canari commander (``canari``) script provides all of the functionality to create, debug, execute, distribute, and +install transforms. The ``canari`` commander provides the following set of commands: + ++--------------------------+-------------------------------------------------------------------------------------------+ +| Canari Command | Description | ++==========================+===========================================================================================+ +| :ref:`create-package` | Creates a Canari transform package skeleton. | ++--------------------------+-------------------------------------------------------------------------------------------+ +| :ref:`create-transform` | Creates a new transform in the specified directory and auto-updates ``__init__.py``. | ++--------------------------+-------------------------------------------------------------------------------------------+ +| :ref:`csv2sheets` | Convert mixed entity type CSVs to separated CSV sheets. | ++--------------------------+-------------------------------------------------------------------------------------------+ +| :ref:`debug-transform` | Runs Canari local transforms in a terminal-friendly fashion. | ++--------------------------+-------------------------------------------------------------------------------------------+ +| :ref:`delete-transform` | Deletes a transform in the specified directory and auto-updates ``__init__.py``. | ++--------------------------+-------------------------------------------------------------------------------------------+ +| :ref:`generate-entities` | Converts Maltego entity definition files to Canari python classes. Excludes Maltego | +| | built-in entities. | ++--------------------------+-------------------------------------------------------------------------------------------+ +| :ref:`help` | Provides detailed help on a specific command (alias for ``-h`` option in all commands). | ++--------------------------+-------------------------------------------------------------------------------------------+ +| :ref:`install-package` | Installs and configures Canari transform packages in Maltego's UI | ++--------------------------+-------------------------------------------------------------------------------------------+ +| :ref:`list-commands` | Lists all the available Canari commands | ++--------------------------+-------------------------------------------------------------------------------------------+ +| :ref:`mtgx2csv` | Convert Maltego graph files (``*.mtgx``) to comma-separated values (CSV) file. | ++--------------------------+-------------------------------------------------------------------------------------------+ +| :ref:`rename-transform` | Renames a transform in the specified directory and auto-updates ``__init__.py``. | ++--------------------------+-------------------------------------------------------------------------------------------+ +| :ref:`run-server` | Runs a transform server for the given packages. | ++--------------------------+-------------------------------------------------------------------------------------------+ +| :ref:`run-transform` | Runs Canari local transforms in a terminal-friendly fashion. | ++--------------------------+-------------------------------------------------------------------------------------------+ +| :ref:`shell` | Creates a Canari debug shell for the specified transform package. | ++--------------------------+-------------------------------------------------------------------------------------------+ +| :ref:`uninstall-package` | Uninstalls and unconfigures canari transform packages in Maltego's UI | ++--------------------------+-------------------------------------------------------------------------------------------+ + + +Canari Commands +--------------- + +The following subsections provide detailed information on each of the ``canari`` commands. Each of these commands accept +an additional ``-h`` argument that is an alias to the ``help`` command. + + +.. _list-commands: + +``list-commands`` +^^^^^^^^^^^^^^^^^ + +The ``list-commands`` command accepts lists all of the available ``canari`` commands along with a brief description. It +accepts no parameters:: + + $ canari list-commands + create-package - Creates a Canari transform package skeleton. + create-transform - Creates a new transform in the specified directory and auto-updates __init__.py. + csv2sheets - Convert mixed entity type CSVs to separated CSV sheets. + debug-transform - Runs Canari local transforms in a terminal-friendly fashion. + delete-transform - Deletes a transform in the specified directory and auto-updates __init__.py. + generate-entities - Converts Maltego entity definition files to Canari python classes. Excludes Maltego built-in entities. + install-package - Installs and configures canari transform packages in Maltego's UI + list-commands - Lists all the available canari commands + mtgx2csv - Convert Maltego graph files (*.mtgx) to comma-separated values (CSV) file. + rename-transform - Renames a transform in the specified directory and auto-updates __init__.py. + run-server - Runs a transform server for the given packages. + run-transform - Runs Canari local transforms in a terminal-friendly fashion. + shell - Creates a Canari debug shell for the specified transform package. + uninstall-package - Uninstalls and unconfigures canari transform packages in Maltego's UI + ... + +.. _help: + +``help`` +^^^^^^^^ + +The ``help`` command displays detailed help on a specific ``canari`` command. It accepts the following parameters: + +* ```` (**required**): the name of the ``canari`` command you're seeking help for. + +The following example illustrates the use of the ``canari help`` command to display detailed help for the +``run-transform`` command:: + + $ canari help run-transform + usage: canari run-transform [param1 ... paramN] [field1=value1...#fieldN=valueN] + + Runs Canari local transforms in a terminal-friendly fashion. + + positional arguments: + The name of the transform you wish to run (e.g. + sploitego.transforms.nmapfastscan). + The value of the input entity being passed into the + local transform. + [param1 ... paramN] Any extra parameters that can be sent to the local + transform. + [field1=value1...#fieldN=valueN] + The fields of the input entity being passed into the + local transform. + + optional arguments: + -h, --help show this help message and exit + +.. _run-transform: + +``run-transform`` +^^^^^^^^^^^^^^^^^ + +The ``run-transform`` command loads and executes the specified local transform module, returning transform results to +the Maltego UI. It accepts the following parameters: + +* ```` (**required**): the name of the python module that contains the local transform data mining + logic (e.g. :py:mod:`sploitego.transforms.whatismyip`) +* ``[param1 ... paramN]`` (**optional**): any extra local transform parameters that can be parsed using + :py:mod:`argparse` (e.g. ``-p 80``) +* ```` (**required**): the value of the entity being passed into the local transform (e.g. ``google.com``) +* ``[field1=value1...#fieldN=valueN]`` (**optional**): optionally, any entity field values delimited by # (e.g. + ``url=http://www.google.ca#public=true``) + +The following example illustrates the use of ``canari run-transform`` to execute the :py:mod:`sploitego.transforms.whatismyip` +transform module that comes bundled with the `Sploitego `_ transform package:: + + $ canari run-transform sploitego.transforms.whatismyip - + 192.168.0.200 + 1true + de:ad:be:ef:fe:ed + + +.. _debug-transform: + +``debug-transform`` +^^^^^^^^^^^^^^^^^^^ + +The ``debug-transform`` command operates in the same fashion as the :ref:`run-transform` command but outputs the result +in a terminal friendly manner. The following example illustrates the use of ``canari debug-transform`` to execute the +:py:mod:`sploitego.transforms.nmapfastscan` transform module on ``www.google.ca``:: + + $ canari run-transform sploitego.transforms.nmapfastscan www.google.com + `- MaltegoTransformResponseMessage: + `- Entities: + `- Entity: {'Type': 'sploitego.Port'} + `- Value: 80 + `- Weight: 1 + `- AdditionalFields: + `- Field: TCP {'DisplayName': 'Protocol', 'Name': 'protocol', 'MatchingRule': 'strict'} + `- Field: Open {'DisplayName': 'Port Status', 'Name': 'port.status', 'MatchingRule': 'strict'} + `- Field: 173.194.75.147 {'DisplayName': 'Destination IP', 'Name': 'ip.destination', 'MatchingRule': 'strict'} + `- Field: syn-ack {'DisplayName': 'Port Response', 'Name': 'port.response', 'MatchingRule': 'strict'} + `- IconURL: file:///Library/Python/2.6/site-packages/canari-1.0-py2.6.egg/canari/resources/images/networking/openport.gif + `- DisplayInformation: + `- Label: http {'Type': 'text/text', 'Name': 'Service Name'} + `- Label: table {'Type': 'text/text', 'Name': 'Method'} + ... + + +.. _run-server: + +``run-server`` +^^^^^^^^^^^^^^ + +The ``run-server`` command loads one or more transform packages and handles remote transform requests brokered by a +`Transform Distribution Server (TDS) `_ via port 80 or 443 (if SSL enabled). ``run-server`` +provides similar functionality to the `Paterva Transform Application Server `_. It accepts the +following parameters: + +* ```` (**required**): The name of the transform packages you wish to host (e.g. :py:mod:`mypkg.transforms`). +* ``--port `` (**optional**): The port the server will run on (default: 443; or 80 if SSL is disabled). +* ``--disable-ssl`` (**optional**): Any extra parameters that can be sent to the local transform. +* ``--enable-privileged`` (**optional**): permit TAS to run packages that require elevated privileges. +* ``--listen-on
`` (**optional**): The address of the interface to listen on. +* ``--cert `` (**optional**): The name of the certificate file used for the server in PEM format. +* ``--hostname `` (**optional**): The hostname of this transform server. +* ``--daemon`` (**optional**): Daemonize server (fork to background). + +The following example illustrates the use of ``canari run-server`` to operate a transform application server to serve +transform requests for transforms belonging to the :py:mod:`sploitego` transform package:: + + $ canari run-server sploitego --disable-ssl + You must run this server as root to continue... + Loading transform packages... + Loading transform package sploitego.transforms + WARNING: No route found for IPv6 destination :: (no default route?) + Loading sploitego.transforms.bcsitereview at /sploitego.transforms.bcsitereview... + Loading sploitego.transforms.sitereputation at /sploitego.transforms.sitereputation... + Starting web server on :80... + Really? Over regular HTTP? What a shame... + + +.. note:: + + ``run-server`` will automatically ask for ``root`` credentials if the server is listening on ports in the reserved + range (0-1024) or if any of the transform modules within the specified transform package is decorated with the + :py:func:`@superuser` decorator and ``--enable-privileged`` is set. + +.. _install-package: + +``install-package`` +^^^^^^^^^^^^^^^^^^^ + +The ``install-package`` command installs and configures a transform package (transforms, entities, Maltego machines) in +the Maltego UI. It accepts the following parameters: + +* ```` (**required**): name of the transform package that contains transform modules (i.e. ``canari``). +* ``-s [dir]``, ``--settings-dir=[dir]`` (**optional**): the name of the directory that contains Maltego's settings. + +.. note:: + + The Maltego settings directory is typically located in the following locations: + + * **Linux**: ``~/.maltego/`` (i.e. ``~/.maltego/3.2.0``) + * **Mac OS/X**: ``~/Library/Application\ Support/maltego/`` (i.e. ``~/Library/Application\ Support/maltego/3.2.0``) + +* ``-w [dir]``, ``--working-dir=[dir]`` (**optional, default: current working directory**): the default working + directory for the Maltego transforms. + +The following example illustrates the use of ``canari install-package`` command to install transforms from the +:py:mod:`sploitego` transform package:: + + $ canari install-package sploitego + Installing transform sploitego.v2.NmapReportToBanner_Amap from sploitego.transforms.amap... + Installing transform sploitego.v2.WebsiteToSiteCategory_BlueCoat from sploitego.transforms.bcsitereview... + Installing transform sploitego.v2.DomainToDNSName_Bing from sploitego.transforms.bingsubdomains... + Installing transform sploitego.v2.DNSNameToIPv4Address_DNS from sploitego.transforms.dnsalookup... + Installing transform sploitego.v2.IPv4AddressToDNSName_CacheSnoop from sploitego.transforms.dnscachesnoop... + Installing transform sploitego.v2.NSRecordToDNSName_CacheSnoop from sploitego.transforms.dnscachesnoop... + ... + +.. warning:: + + You must have initialized Maltego for the first time before attempting to install a transform package using + ``install-package``. Otherwise, the installation will fail. + +.. warning:: + + **DO NOT** run ``canari install-package`` as ``root`` unless you intend to run Maltego as ``root`` at all times. + +.. _uninstall-package: + +``uninstall-package`` +^^^^^^^^^^^^^^^^^^^^^ + +The ``uninstall-package`` command uninstalls and un-configures all the local transform modules within the specified +transform package in the Maltego UI. It accepts the following parameters: + +* ```` (**required**): name of the transform package that contains transform modules. (i.e. :py:mod:`sploitego`) +* ``-s [dir]``, ``--settings-dir=[dir]`` (**optional**): the name of the directory that contains Maltego's settings + (i.e. ``~/.maltego/`` in Linux, ``~/Library/Application\ Support/maltego/`` in Mac OS X) + +The following example illustrates the use of ``canari uninstall-package`` to uninstall transforms from the +:py:mod:`sploitego` transform package:: + + $ canari uninstall-package sploitego + Multiple versions of Maltego detected: + [0] Maltego v3.1.1 + [1] Maltego v3.1.1CE + Please select which version you wish to install the transforms in [0]: 1 + Uninstalling transform sploitego.v2.NmapReportToBanner_Amap from sploitego.transforms.amap... + Uninstalling transform sploitego.v2.WebsiteToSiteCategory_BlueCoat from sploitego.transforms.bcsitereview... + Uninstalling transform sploitego.v2.DomainToDNSName_Bing from sploitego.transforms.bingsubdomains... + Uninstalling transform sploitego.v2.DNSNameToIPv4Address_DNS from sploitego.transforms.dnsalookup... + Uninstalling transform sploitego.v2.IPv4AddressToDNSName_CacheSnoop from sploitego.transforms.dnscachesnoop... + Uninstalling transform sploitego.v2.NSRecordToDNSName_CacheSnoop from sploitego.transforms.dnscachesnoop... + +.. _shell: + +``shell`` +^^^^^^^^^ + +The canari shell script offers an interactive shell for running transforms (work in progress). It accepts the following +parameters: + +* ```` (**required**): the name of the transform package to load. + +The following example illustrates the use of canari shell to run transforms from the sploitego transform package:: + + $ canari shell sploitego + Welcome to Canari. + mtg> whatismyip('4.2.2.1') + `- MaltegoTransformResponseMessage: + `- Entities: + `- Entity: {'Type': 'maltego.IPv4Address'} + `- Value: 10.0.1.22 + `- Weight: 1 + `- AdditionalFields: + `- Field: true {'DisplayName': 'Internal', 'Name': 'ipaddress.internal', 'MatchingRule': 'strict'} + `- Field: 68:a8:6d:4e:0f:72 {'DisplayName': 'Hardware Address', 'Name': 'ethernet.hwaddr', 'MatchingRule': 'strict'} + mtg> + +.. _create-package: + +``create-package`` +^^^^^^^^^^^^^^^^^^ + +The ``create-package`` command generates a transform package skeleton for eager transform developers. It accepts the +following parameters: + +* ```` (**required**): the desired name of the transform package you wish to develop. + +The following example illustrates the use of ``canari create-package`` to create a transform package named +:py:mod:`foobar`:: + + $ canari create-package foobar + creating skeleton in foobar + creating directory foobar + creating directory foobar/src + creating directory foobar/maltego + creating directory foobar/src/foobar + creating directory foobar/src/foobar/transforms + creating directory foobar/src/foobar/transforms/common + creating directory foobar/src/foobar/resources + creating directory foobar/src/foobar/resources/etc + creating directory foobar/src/foobar/resources/images + creating file foobar/setup.py... + creating file foobar/README.md... + creating file foobar/src/foobar/__init__.py... + creating file foobar/src/foobar/resources/__init__.py... + creating file foobar/src/foobar/resources/etc/__init__.py... + creating file foobar/src/foobar/resources/images/__init__.py... + creating file foobar/src/foobar/resources/etc/foobar.conf... + creating file foobar/src/foobar/transforms/__init__.py... + creating file foobar/src/foobar/transforms/helloworld.py... + creating file foobar/src/foobar/transforms/common/__init__.py... + creating file foobar/src/foobar/transforms/common/entities.py... + done! + + +.. _create-transform: + +``create-transform`` +^^^^^^^^^^^^^^^^^^^^ + +The ``create-transform`` command generates a transform module and automatically adds it to the ``__init__.py`` file in a +transform package. It accepts the following parameters: + +* ```` (**required**): the desired name of the transform module to create. + +The following example illustrates the use of ``canari create-transform`` to create a transform module named +:py:mod:`cooltransform`:: + + $ cd foobar/src/foobar/transforms/ + $ canari create-transform cooltransform + creating file ./cooltransform.py... + updating __init__.py + done! + +.. _rename-transform: + +``rename-transform`` +^^^^^^^^^^^^^^^^^^^^ + +The ``rename-transform`` command renames a transform module and automatically updates the corresponding ``__init__.py`` +file entry in a transform package. It accepts the following parameters: + +* ```` (**required**): the name of the transform module to rename. +* ```` (**required**): the new desired name of the transform module. + +The following example illustrates the use of ``canari rename-transform`` to rename a transform module named +:py:mod:`cooltransform` to :py:mod:`mytransform`:: + + $ cd foobar/src/foobar/transforms/ + $ canari rename-transform cooltransform mytransform + renaming transform '/home/foo/foobar/src/foobar/transforms/cooltransform.py' to '/home/foo/foobar/src/foobar/transforms/mytransform.py'... + updating /home/foo/foobar/src/foobar/transforms/__init__.py + done! + + +.. _delete-transform: + +``delete-transform`` +^^^^^^^^^^^^^^^^^^^^ + +The ``delete-transform`` command deletes a transform module and automatically removes the corresponding ``__init__.py`` +file entry in a transform package. It accepts the following parameters: + +* ```` (**required**): the name of the transform module to delete. + +The following example illustrates the use of ``canari delete-transform`` to delete a transform module named +:py:mod:`mytransform`:: + + $ cd foobar/src/foobar/transforms/ + $ canari delete-transform mytransform + deleting transform '/home/foo/foobar/src/foobar/transforms/poop.py'... + updating /home/foo/foobar/src/foobar/transforms/__init__.py + done! + + +.. _generate-entities: + +``generate-entities`` +^^^^^^^^^^^^^^^^^^^^^ + +The ``generate-entities`` command generates the Python/Canari definitions of the entities contained within Maltego or a +Maltego entity export file (``*.mtz``) and writes the result to a file. The entities within the ``maltego`` namespace +(or builtin entities) are automatically excluded and only custom entity definitions are generated. It accepts the +following parameters: + +* ```` (**optional**): Which file to write the output to (default: ``entities.py``). +* ``--mtz-file ``, ``-m `` (**optional**): A ``*.mtz`` file containing an export of Maltego entities. +* ``--exclude-namespace ``, ``-e `` (**optional**): Name of Maltego entity namespace to ignore. + Can be defined multiple times. +* ``--namespace ``, ``-n `` (**optional**): Name of Maltego entity namespace to generate entity + classes for. Can be defined multiple times. +* ``--append``, ``-a`` (**optional**): Whether or not to append to the existing ``entities.py`` file. +* ``--entity ``, ``-E `` (**optional**): Name of Maltego entity to generate Canari python class for. + +If no arguments are passed, the ``generate-entities`` command will load the entity definition files from Maltego's +setting directory and automatically generate an ``entities.py`` file in the current working directory. + +.. warning:: + + The ``generate-entities`` command will overwrite the current ``entities.py`` file if executed with no arguments in + the ``src//transforms/common`` directory. + + +.. _mtgx2csv: + +``mtgx2csv`` +^^^^^^^^^^^^ + +The ``mtgx2csv`` command generates a comma-separated report (CSV) of a Maltego-generated graph. It accepts the +following parameters: + +* ```` (**required**): the name of the Maltego graph file. + +The following example illustrates the use of ``canari mtgx2csv`` to create a CSV report of a Maltego graph file named +``Graph1.mtgx``:: + + $ canari mtgx2csv ``Graph1.mtgx`` + $ ls *.csv + Graph1.csv + +.. _csv2sheets: + +``csv2sheets`` +^^^^^^^^^^^^^^ + +The ``csv2sheets`` command separates the CSV report file into multiple CSV files containing entities of the same type. +It accepts the following parameters: + +* ```` (**required**): the name of the CSV report generated by ``canari mtgx2csv`` +* ```` (**required**): a prefix to prepend to the generated CSV files. + +The following example illustrates the use of ``canari csv2sheets`` to create a CSV files containing entities of the same +type from the CSV report Graph1.csv:: + + $ csv2sheets Graph1.csv IRS + $ ls *.csv + Graph1.csv IRS_0.csv IRS_1.csv ... \ No newline at end of file diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..8c38409 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,246 @@ +# -*- coding: utf-8 -*- +# +# canari documentation build configuration file, created by +# sphinx-quickstart on Sat Aug 25 19:44:54 2012. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +sys.path.insert(0, os.path.abspath('../src/')) + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.intersphinx'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'canari' +copyright = u'2012, Canari Project' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '1.0' +# The full version, including alpha/beta/rc tags. +release = '1.0' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'default' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'canaridoc' + + +# -- Options for LaTeX output -------------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('index', 'canari.tex', u'Canari Framework Documentation', + u'Nadeem Douba', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output -------------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'canari', u'Canari Framework Documentation', + [u'Nadeem Douba'], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------------ + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ('index', 'canari', u'Canari Framework Documentation', + u'Nadeem Douba', 'canari', 'A slick and easy Maltego local transform framework.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = {'http://docs.python.org/': None} diff --git a/docs/development.rst b/docs/development.rst new file mode 100644 index 0000000..07f5552 --- /dev/null +++ b/docs/development.rst @@ -0,0 +1,433 @@ +################################ +Transform Development Quickstart +################################ + +Developing local and remote transforms is a cinch with :py:mod:`canari`. Whether you want to develop a whole bunch of +transforms or just one, you'll probably want to take advantage of :py:mod:`canari`'s amazing features. So let's get +started with a quick tutorial on how you can take advantage of :py:mod:`canari`'s powerful transform framework. The +following sections will give you a quick-start tutorial on how to develop transforms. + +Creating a Transform Package +============================ + +We'll just go ahead and create a transform package called :py:mod:`mypackage`:: + + $ canari create-package mypackage + creating skeleton in mypackage + creating file setup.py... + creating file README.md... + creating file src/mypackage/transforms/common/entities.py... + creating file src/mypackage/transforms/helloworld.py... + creating file src/mypackage/__init__.py... + creating file src/mypackage/transforms/__init__.py... + creating file src/mypackage/transforms/common/__init__.py... + done! + + +You'll notice that a simple skeleton project was generated, with a :py:mod:`helloworld` transform to get you started. +You can test the :py:mod:`helloworld` transform module right away by running `canari debug-transform` like so:: + + + $ canari debug-transform mypackage.transforms.helloworld Phil + %50 + D:This was pointless! + %100 + `- MaltegoTransformResponseMessage: + `- Entities: + `- Entity: {'Type': 'test.MyTestEntity'} + `- Value: Hello Phil! + `- Weight: 1 + `- AdditionalFields: + `- Field: 2 {'DisplayName': 'Field 1', 'Name': 'test.field1', 'MatchingRule': 'strict'} + `- Field: test {'DisplayName': 'Field N', 'Name': 'test.fieldN', 'MatchingRule': 'strict'} + + +Developing a Transform +====================== + +Let's take a look at an abbreviated version of ``src/mypackage/transforms/helloworld.py``, from our example above, +to see how this transform was put together: + +.. code-block:: python + + #!/usr/bin/env python + + from canari.maltego.message import Person + from canari.maltego.utils import debug, progress + from canari.framework import configure #, superuser + from common.entities import MypackageEntity + + # ... + #@superuser + @configure( + label='To MypackageEntity [Hello World]', + description='Returns a MyPackageEntity entity with the phrase "Hello Word!"', + uuids=[ 'mypackage.v2.MyPackageEntityToPhrase_HelloWorld' ], + inputs=[ ( 'MyPackageEntity', Person ) ], + debug=True + ) + def dotransform(request, response): + # Report transform progress + progress(50) + # Send a debugging message to the Maltego UI console + debug('This was pointless!') + + # Create MyPackageEntity entity with value set to 'Hello !' + e = MypackageEntity('Hello %s!' % request.value) + + # Setting field values on the entity + e.field1 = 2 + e.fieldN = 'test' + + # Update progress + progress(100) + + # Add entity to response object + response += e + + # Return response for visualization + return response + + + def onterminate(): + debug('Caught signal... exiting.') + exit(0) + + +Right away, you notice that there are a whole bunch of decorators (or annotations) and two functions +(:py:func:`dotransform` and :py:func:`onterminate`). So what does this all mean and how does it work? Let's focus on the +meat, shall we? + +The :py:func:`dotransform` function is the transform's entry point, this is where all the fun stuff happens. This +transform isn't particularly fun, but it serves as a good example of what typically happens in a canari transform. +:py:func:`dotransform` takes two arguments, :py:obj:`request` and :py:obj:`response`. The :py:obj:`request` object +contains the data passed by Maltego to the local transform and is parsed and stored into the following properties: + +.. py:attribute:: value + + A string containing the value of the input entity. + +.. py:attribute:: fields + + A dictionary of entity field names and their respective values of the input entity. + +.. py:attribute:: params + + A list of any additional command-line arguments to be passed to the transform. + +The :py:obj:`response` object is what our data mining logic will populate with entities and it is of type +:py:class:`MaltegoTransformResponseMessage`. The :py:obj:`response` object is very neat in the sense that it can do +magical things with data. With simple arithematic operations (``+=``, ``-=``, ``+``, ``-``), one can add/remove entities +or Maltego UI messages. You'll probably want to use the ``+=`` or ``-=`` operators because ``-`` and ``+`` create +a new :py:class:`MaltegoTransformResponseMessage` object and that can be costly. Let's take a look at how it works in +the transform above: + +.. code-block:: python + + # ... + e = MypackageEntity('Hello %s!' % request.value) + # ... + response += e + # ... + + +The first line of code, creates a new :py:class:`MypackageEntity` object is created with a value +``'Hello !'``. The second line of code adds the newly created object, :py:data:`e`, to the +:py:obj:`response` object. If we serialize the object into XML we'd see the following (spaced for clarity) output: + +.. code-block:: xml + + + + + + Hello Phil! + 1 + + 2 + test + + + + + + + +You may be wondering where those fields (``mypackage.field1`` and ``mypackage.fieldN``) came from? Simple, from here: + +.. code-block:: python + + # ... + e.field1 = 2 + e.fieldN = 'test' + # ... + + +If your feeling eager, see :ref:`custom-entity` for more information on how those properties came to fruition. + +Once :py:func:`dotransform` is called, the data mining logic does it's thing and adds entities to the +:py:obj:`response` object if necessary. Finally, the :py:obj:`response` is returned and :program:`dispatcher` +serializes the object into XML. What about the decorators (:py:func:`@configure` and :py:func:`@superuser`)? +Read on... + + +``canari install-package`` Magic (:py:func:`@configure`) +----------------------------------------------------------- + +So how does ``canari install-package`` figure out how to install and configure the transform in Maltego's UI? Simple, +just use the :py:func:`@configure` decorator on your :py:func:`dotransform` function and ``canari install`` will take +care of the rest. The :py:func:`@configure` decorator tells ``canari install-package`` how to install the transform +in Maltego. It takes the following named parameters: + +.. py:function:: @configure(**kwargs) + + :keyword str label: The name of the transform as it appears in the Maltego UI transform selection menu. + :keyword str description: A short description of the transform. + :keyword list uuids: A list of unique transform IDs, one per input type. The order of this list must match that of + the inputs parameter. Make sure you account for entity type inheritance in Maltego. For example, + if you choose a :py:class:`DNSName` entity type as your input type you do not need to specify it + again for :py:class:`MXRecord`, :py:class:`NSRecord`, etc. + :keyword list inputs**: A list of tuples where the first item is the name of the transform set the transform should + be part of, and the second item is the input entity type. + :keyword bool debug: Whether or not the debugging window should appear in Maltego's UI when running the transform. + +Let's take a look at the code again from the example above: + +.. code-block:: python + + # ... + @configure( + label='To MypackageEntity [Hello World]', + description='Returns a MyPackageEntity entity with the phrase "Hello Word!"', + uuids=[ 'mypackage.v2.MyPackageEntityToPhrase_HelloWorld' ], + inputs=[ ( 'Mypackage', Person ) ], + debug=True + ) + def dotransform(request, response): + # ... + + +The example above tells ``canari install-package`` to process the transform in the following manner: + +#. The name of the transform in the transform selection context menu should appear as + ``To MypackageEntity [Hello World]`` in Maltego's UI. +#. The short description of the transform as it appears in Maltego's UI is ``Returns a MyPackageEntity entity with the + phrase "Hello Word!"``. +#. The transform ID of the transform in Maltego's UI will be ``mypackage.v2.MyPackageEntityToPhrase_HelloWorld``. and + will only work with an input entity type of :py:class:`Person` belonging to the ``Mypackage`` transform set. +#. Finally, Maltego should pop a debug window on transform execution. + +What if we wanted this transform to work for entity types of :py:class:`Location`, as well. Simple, just add another +``uuid`` and ``input`` tuple like so: + +.. code-block:: python + + # ... + @configure( + label='To MypackageEntity [Hello World]', + description='Returns a MyPackageEntity entity with the phrase "Hello Word!"', + uuids=[ 'mypackage.v2.MyPackageEntityToPhrase_HelloWorld', 'mypackage.v2.MyPackageEntityToLocation_HelloWorld' ], + inputs=[ ( 'Mypackage', Person ), ( 'Mypackage', Location ) ], + debug=True + ) + def dotransform(request, response): + # ... + + +Now you have one transform configured to run on two different input entity types (:py:class:`Person` and +:py:class:`Location`) with just a few lines of code and you can do this as many times as you like! Awesome! + + +Running as Root (:py:func:`@superuser`) +--------------------------------------- + +At some point you may want to run your transform using a super-user account in UNIX-based environments. Maybe to run +something cool like :program:`Metasploit` or :program:`Nmap`. You can do that simply by decorating +:py:func:`dotransform` with :py:func:`@superuser`: + +.. code-block:: python + + # ... + @superuser + @configure( + # ... + ) + def dotransform(request, response): + # ... + + +This will instruct :program:`dispatcher` to run the transform using :program:`sudo`. If :program:`dispatcher` is not +running as ``root`` a :program:`sudo` password dialog box will appear asking the user to enter their password. +If successful, the transform will run as root, just like that! + +Renaming Transforms with ``canari rename-transform`` +------------------------------------------------------- + +Alright, so you got a bit excited and decided to re-purpose the :py:mod:`helloworld` transform module to do something +cool. In you're bliss you decided to change the name of the transform module to ``mycooltransform.py``. So you're all +set to go, right? **Wrong**, you'll need to change the entry in the :py:data:`__all__` variable (i.e. ``'helloworld'`` +-> ``'mycooltransform'``) in ``src/mypackage/transforms/__init__.py``, first. Why? Because ``canari install-package`` +will only detect transforms if they are listed in the :py:data:`__all__` variable of the transform package's +``__init__.py`` script. You can do this quite simply by running:: + + $ pwd + /home/user1/foo/src/foo/transforms + $ canari rename-transform helloworld mycooltransform + renaming transform 'helloworld' to 'mycooltransform'... + updating __init__.py + done! + + +Creating and Removing Transforms +-------------------------------- + +So you want to create another transform but you want to be speedy like Gonzalez. You don't want to keep writing out the +same thing for each transform. No problem, ``canari create-transform`` will give you a head start. +``canari create-transform`` generates a bare bones transform module that you can hack up to do whatever you like. +Just run ``canari create-transform`` in the ``src/mypackage/transforms`` directory, like so:: + + $ cd src/mypackage/transforms + $ canari create-transform mysecondcooltransform + creating file ./mysecondcooltransform.py... + updating __init__.py + done! + + +No need to add the entry in ``__init__.py`` anymore because ``canari create-transform`` does it for you +automagically. The same is true for ``canari delete-transform`` if you want to remove a transform from your package. + + +.. _custom-entity: + +Creating Custom Entities +======================== + +Now you want to get a custom entity in. No problem! We've got that covered too. With just a few lines of code you can +create as many entities as you wish. The only gotcha in this process is that you'll probably want to iconify these +entities so they look good in Maltego. That's a manual process we can't get away from. On the other hand, defining +custom entities in your code is quite simple. Take a look inside your custom package's +``src/mypackage/transforms/common/entities.py`` file. It should look similar to this: + +.. code-block:: python + + #!/usr/bin/env python + + from canari.maltego.message import Entity, EntityField, EntityFieldType, MatchingRule + + # ... + + """ + DO NOT EDIT + ... + """ + class FooEntity(Entity): + namespace = 'foo' + + + """ + TODO + ... + """ + @EntityField(name='foo.fieldN', propname='fieldN', displayname='Field N', matchingrule=MatchingRule.Loose) + @EntityField(name='foo.field1', propname='field1', displayname='Field 1', type=EntityFieldType.Integer) + class MyFooEntity(FooEntity): + # ... + # name = my.fancy.EntityType + pass + +You may be asking yourself "That's it?" or maybe even scratching your head about what this all means. Don't worry, we'll +go through this line-by-line. The first class, :py:class:`FooEntity` is the base entity class for all your custom +entities. You won't want to edit this much since all it provides is a custom namespace for your entities. What is a +namespace? If you've designed a custom entity in Maltego you probably noticed that the entity gets a suggested ID of +``.``. In this case the namespace is the ```` portion of the entity's ID. This is done +to avoid conflicts between different entity definitions from various transform developers. Maltego's built-in entities +have a namespace of ``maltego``. In our case, the namespace for all of our entities will be ``foo``. + +What about the other entity, :py:class:`MyFooEntity`? That's just an example entity definition that you can modify to +your heart's content. Notice the :py:func:`@EntityField` decorators. Those define the structure of the entity in terms +of what entity fields exist, their data-types, icon decorators, and various other elements that affect how Maltego +compares two different entities of the same type. In addition, these decorators synthesize class fields identified by +the ``propname`` keyword argument. Modifying their values is as easy as ``myfooentity.mypropname``. + +You can specify as many entity fields as you want by just adding an extra :py:func:`@EntityField` decorator to your +entities. The :py:func:`@EntityField` decorator takes the following parameters: + +.. py:function:: @EntityField(**kwargs) + + :keyword str name: the name of the field without spaces or special characters except for dots ('.') (required). + :keyword str propname: the name of the object's property used to get and set the value of the field + (required, if name contains dots) + :keyword str displayname: the name of the entity as it appears in Maltego (optional). + :keyword str type: the data type of the field (optional, default: EntityFieldType.String). + :keyword bool required: whether or not the field's value must be set before sending back the message (optional, + default: False). + :keyword list choices: a list of acceptable field values for this field (optional). + :keyword str matchingrule: whether or not the field should be loosely or strictly matched by Maltego's graphing + engine (optional, default: MatchingRule.Strict). + :keyword callable decorator: a function that is invoked each and every time the field's value is set or changed. + + +Matching Rules +-------------- + +Maltego currently supports two types of matching rules for entities: ``strict`` and ``loose``. These rules apply to an +entity's fields and determine how Maltego graph two entities of the same type and value but with differing entity field +values on a graph. For example, let's assume you've performed a transform that produced two ``IPv4Address`` entities on +a graph with the same entity value of ``127.0.0.1``. Each ``IPv4Address`` entity has an ``internal`` boolean field +which indicates whether or not the ``IPv4Address`` entity represents an internal IP address. Let's assume that the +``internal`` fields are different, one is set to ``true`` and the other to ``false``. In the case where the ``internal`` +field is ``loose``'ly matched, both entities would appear as one entity on the graph. Otherwise, if the ``internal`` +field is ``strict``'ly matched, then both these entities would appear as two separate entities on the graph. If you're a +fan of a visual example, try the following example transform out to see what the end results are: + +.. code-block:: python + + #!/usr/bin/env python + + from canari.maltego.message import Entity, MatchingRule + from canari.maltego.message import Phrase, Field + from canari.framework import configure + + + class TestEntity(Entity): + namespace='test' + + class MyIPv4Address(TestEntity): + pass + + + @configure( + label='To IPv4Address [Matching Rules]', + description='Shows how matching rules work in Maltego.', + uuids=[ 'tests.v2.PhraseToIPv4Address_Matching_Rules' ], + inputs=[ ( 'Testing Matching Rules', Phrase ) ], + debug=True + ) + def dotransform(request, response): + + # What kind of matching rule are we using? + mr = MatchingRule.Strict + if request.value.lower() == 'loose': + mr = MatchingRule.Loose + + # First IP + ip1 = MyIPv4Address('127.0.0.1') + ip1 += Field('internal', 'true', matchingrule=mr) + response += ip1 + + # Second IP + ip2 = MyIPv4Address('127.0.0.1') + ip2 += Field('internal', 'false', matchingrule=mr) + response += ip2 + + # Return response for visualization + return response + + +The example transform runs on ``Phrase`` entities and determines its matching rule based on the ``Phrase`` entity's +value. If it is anything other than ``loose``, the entity field ``internal`` will be ``strict``'ly matched. + +Entity Field Decorators +----------------------- + +Say you want to provide users of your transforms with better visuals for your transform outputs. For example, \ No newline at end of file diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..98d42c8 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,21 @@ +Canari Framework +================ + +Contents: + +.. toctree:: + :maxdepth: 2 + :numbered: + + intro + canari + development + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + diff --git a/docs/intro.rst b/docs/intro.rst new file mode 100644 index 0000000..d1ac540 --- /dev/null +++ b/docs/intro.rst @@ -0,0 +1,134 @@ + +Introduction +============ + +Welcome to the official documentation for the `Canari Framework `_. The +`Canari Framework `_ is a rapid transform development framework that can be used to develop +**local and remote** transforms for `Maltego `_ . Designed on the principles of convention over +configuration, developing transforms using Canari is extremely fast and easy. Canari takes care of XML serialization and +deserialization, argument or parameter parsing, as well as transform configuration and execution. Not only is Canari +great for Maltego transform development but it is also extremely easy to test, debug, and distribute your transforms. +Canari provides a powerful transform package specification that makes local transform distribution a cinch. Installing a +set of Maltego transforms, entities, and Maltego Scripts (or Machines) is as easy as typing one line in your terminal. +Even if you're not a Python developer, Canari has support for easily distributing transforms written in different +languages (i.e. PERL, Java, Ruby, etc.). The following subsections will provide an in-depth look of Canari's features, +libraries, and transform package specification. + + +Terminology +----------- + +Before we get started with the documentation, it might be useful to introduce some of the terminology that will be used +throughout the documentation: + ++-----------------------+----------------------------------------------------------------------------------------------+ +| Term | Definition | ++=======================+==============================================================================================+ +| **Entity** | a piece of information on a Maltego graph represented as a node. | ++-----------------------+----------------------------------------------------------------------------------------------+ +| **Input Entity** | the entity that is being passed into the transform to use for data mining purposes. | ++-----------------------+----------------------------------------------------------------------------------------------+ +| **Output Entity** | the entity that is being returned by the transform to be drawn on a Maltego graph. | ++-----------------------+----------------------------------------------------------------------------------------------+ +| **Transform** | a function that takes one *input entity* as input and returns zero or more *output entities*.| ++-----------------------+----------------------------------------------------------------------------------------------+ +| **Transform Module** | a python module local transform code. | ++-----------------------+----------------------------------------------------------------------------------------------+ +| **Transform Package** | a python package containing one or more transform modules, entities, and Maltego machines. | ++-----------------------+----------------------------------------------------------------------------------------------+ + + +Installing Canari +----------------- + +Canari is officially supported on Python versions 2.6 and 2.7 with `setuptools `_ +on Linux and Mac OS/X. Canari has not yet been tested on Windows but should be able to operate in this environment as +well. To install setuptools in your Python distribution, simply go to ``_ and +download the corresponding Python egg distribution for your operating system and follow the instructions for +installation. Once setuptools is installed, type the following command in your terminal:: + + $ sudo easy_install canari + +This will install of Canari's dependencies (argparse and pexpect) as well as Canari's transform development tool-suite. +If successful, you should be able to run Canari's commander by typing ``canari list-commands`` at the command-prompt:: + + $ canari list-commands + create-package - Creates a Canari transform package skeleton. + create-transform - Creates a new transform in the specified directory and auto-updates __init__.py. + csv2sheets - Convert mixed entity type CSVs to separated CSV sheets. + debug-transform - Runs Canari local transforms in a terminal-friendly fashion. + delete-transform - Deletes a transform in the specified directory and auto-updates __init__.py. + generate-entities - Converts Maltego entity definition files to Canari python classes. Excludes Maltego built-in entities. + install-package - Installs and configures canari transform packages in Maltego's UI + list-commands - Lists all the available canari commands + mtgx2csv - Convert Maltego graph files (*.mtgx) to comma-separated values (CSV) file. + rename-transform - Renames a transform in the specified directory and auto-updates __init__.py. + run-server - Runs a transform server for the given packages. + run-transform - Runs Canari local transforms in a terminal-friendly fashion. + shell - Creates a Canari debug shell for the specified transform package. + uninstall-package - Uninstalls and unconfigures canari transform packages in Maltego's UI + +If you were unable to run the Canari commander then please refer to :ref:`ref_troubleshoot` for information. Otherwise, +let's dive right into the :ref:`ref_canari_commander`. + +.. _ref_troubleshoot: + +Trouble-shooting Canari Installations +------------------------------------- + +In some odd cases, the ``canari`` commander is inaccessible due to erroneous permission or system path definitions. To +troubleshoot this issue ensure the following two conditions are true: + +* The path where ``canari`` is installed (i.e. ``/usr/local/bin``) has read and execute permissions for everyone. +* The system's ``PATH`` environment variable includes the path where ``canari`` has been installed. + +The following subsections provide some pointers for trouble-shooting Canari installations on specific operating systems. + + +Linux and Mac OS/X +^^^^^^^^^^^^^^^^^^ + +To determine the location of your ``canari`` script, check the output of ``easy_install``:: + + $ sudo easy_install canari + ... + Installing canari script to /usr/local/bin + Installing dispatcher script to /usr/local/bin + Installing pysudo script to /usr/local/bin + ... + +Once you've determined the location of the ``canari`` script (e.g. ``/usr/local/bin``), ensure that it is in +your system's ``PATH`` environment variable:: + + $ echo $PATH + /usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin + +If the ``canari`` script's path is not included in your system's ``PATH`` environment variable, then check your +operating system's documentation on how to modify your ``PATH`` environment variable. Otherwise, if the path is in your +system's ``PATH`` environment variable and you are still unable to run ``canari`` then you'll want to ensure that the +``canari`` script's parent directory is accessible by everyone:: + + $ ls -l /usr/local + total 0 + drwxr-xr-x 58 root wheel 1972 7 Jan 23:42 bin + ... + + +Ensure that ``canari``'s parent directory (e.g. ``/usr/local/bin``) has ``755`` permissions. If not, use the following +command to correct the directory's permissions:: + + $ sudo chmod 755 /usr/local/bin + +If none of these steps have helped correct this issue please feel free to send an email to ``_ +for additional help with the following details: + + * Operating system name and version. + * Canari version. + * ``easy_install`` output. + +Windows +^^^^^^^ + +.. note:: + + Canari has not been tested on Windows yet. diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 0000000..a0d6660 --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,190 @@ +@ECHO OFF + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set BUILDDIR=_build +set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . +set I18NSPHINXOPTS=%SPHINXOPTS% . +if NOT "%PAPER%" == "" ( + set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% + set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% +) + +if "%1" == "" goto help + +if "%1" == "help" ( + :help + echo.Please use `make ^` where ^ is one of + echo. html to make standalone HTML files + echo. dirhtml to make HTML files named index.html in directories + echo. singlehtml to make a single large HTML file + echo. pickle to make pickle files + echo. json to make JSON files + echo. htmlhelp to make HTML files and a HTML help project + echo. qthelp to make HTML files and a qthelp project + echo. devhelp to make HTML files and a Devhelp project + echo. epub to make an epub + echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter + echo. text to make text files + echo. man to make manual pages + echo. texinfo to make Texinfo files + echo. gettext to make PO message catalogs + echo. changes to make an overview over all changed/added/deprecated items + echo. linkcheck to check all external links for integrity + echo. doctest to run all doctests embedded in the documentation if enabled + goto end +) + +if "%1" == "clean" ( + for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i + del /q /s %BUILDDIR%\* + goto end +) + +if "%1" == "html" ( + %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/html. + goto end +) + +if "%1" == "dirhtml" ( + %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. + goto end +) + +if "%1" == "singlehtml" ( + %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. + goto end +) + +if "%1" == "pickle" ( + %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the pickle files. + goto end +) + +if "%1" == "json" ( + %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the JSON files. + goto end +) + +if "%1" == "htmlhelp" ( + %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run HTML Help Workshop with the ^ +.hhp project file in %BUILDDIR%/htmlhelp. + goto end +) + +if "%1" == "qthelp" ( + %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run "qcollectiongenerator" with the ^ +.qhcp project file in %BUILDDIR%/qthelp, like this: + echo.^> qcollectiongenerator %BUILDDIR%\qthelp\sploitego.qhcp + echo.To view the help file: + echo.^> assistant -collectionFile %BUILDDIR%\qthelp\sploitego.ghc + goto end +) + +if "%1" == "devhelp" ( + %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. + goto end +) + +if "%1" == "epub" ( + %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The epub file is in %BUILDDIR%/epub. + goto end +) + +if "%1" == "latex" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "text" ( + %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The text files are in %BUILDDIR%/text. + goto end +) + +if "%1" == "man" ( + %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The manual pages are in %BUILDDIR%/man. + goto end +) + +if "%1" == "texinfo" ( + %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. + goto end +) + +if "%1" == "gettext" ( + %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The message catalogs are in %BUILDDIR%/locale. + goto end +) + +if "%1" == "changes" ( + %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes + if errorlevel 1 exit /b 1 + echo. + echo.The overview file is in %BUILDDIR%/changes. + goto end +) + +if "%1" == "linkcheck" ( + %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck + if errorlevel 1 exit /b 1 + echo. + echo.Link check complete; look for any errors in the above output ^ +or in %BUILDDIR%/linkcheck/output.txt. + goto end +) + +if "%1" == "doctest" ( + %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest + if errorlevel 1 exit /b 1 + echo. + echo.Testing of doctests in the sources finished, look at the ^ +results in %BUILDDIR%/doctest/output.txt. + goto end +) + +:end diff --git a/src/canari/commands/common.py b/src/canari/commands/common.py index 6e74b3f..4d89ae7 100644 --- a/src/canari/commands/common.py +++ b/src/canari/commands/common.py @@ -2,7 +2,7 @@ from canari.config import CanariConfigParser -from os import path, listdir, sep, environ, mkdir, pathsep, getcwd +from os import path, listdir, sep, environ, mkdir, pathsep, getcwd, walk from pkg_resources import resource_filename from distutils.dist import Distribution from distutils.command.install import install @@ -91,7 +91,7 @@ def write_template(fname, data): def generate_all(*args): - return "\n__all__ = [\n '%s'\n]" % "',\n '".join(args) + return "\n\n__all__ = [\n '%s'\n]" % "',\n '".join(args) def build_skeleton(*args): @@ -172,9 +172,10 @@ def console_message(msg, tab=-1): def init_pkg(): - conf = '.canari' + root = project_root() - for i in range(0, 5): + if root is not None: + conf = path.join(root, '.canari') if path.exists(conf): c = CanariConfigParser() c.read(conf) @@ -183,10 +184,8 @@ def init_pkg(): 'email' : c['metadata/email'], 'maintainer' : c['metadata/maintainer'], 'project' : c['metadata/project'], - 'year' : datetime.now().year, - 'dir' : getcwd() + 'year' : datetime.now().year } - conf = '..%s%s' % (sep, conf) return { 'author' : '', @@ -197,4 +196,49 @@ def init_pkg(): } +def project_root(): + + marker = '.canari' + + for i in range(0, 5): + if path.exists(marker): + return path.dirname(path.realpath(marker)) + marker = '..%s%s' % (sep, marker) + + print 'Unable to determine project root.' + exit(-1) + + +def project_tree(): + + root = project_root() + + tree = dict( + root=root, + src=None, + pkg=None, + resources=None, + transforms=None + ) + + for base, dirs, files in walk(root): + if base.endswith('src'): + tree['src'] = base + elif 'resources' in dirs: + tree['pkg'] = base + elif base.endswith('resources'): + tree['resources'] = base + elif base.endswith('transforms'): + tree['transforms'] = base + + return tree + + +def parse_bool(ans, default='y'): + while True: + ans = raw_input(ans).lower() or default + if ans.startswith('y'): + return True + elif ans.startswith('n'): + return False \ No newline at end of file diff --git a/src/canari/commands/create_package.py b/src/canari/commands/create_package.py index d6b11e6..2bcb2ed 100644 --- a/src/canari/commands/create_package.py +++ b/src/canari/commands/create_package.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -from common import read_template, write_template, generate_all, build_skeleton, cmd_name +from common import read_template, write_template, generate_all, build_skeleton, cmd_name, parse_bool from argparse import ArgumentParser from datetime import datetime @@ -114,16 +114,6 @@ def description(): return parser.description -def parse_bool(ans, default='y'): - - while True: - ans = raw_input(ans).lower() or default - if ans.startswith('y'): - return True - elif ans.startswith('n'): - return False - - def ask_user(defaults): print('Welcome to the Canari transform package wizard.') diff --git a/src/canari/commands/create_transform.py b/src/canari/commands/create_transform.py index c9a35d5..9e2c39e 100644 --- a/src/canari/commands/create_transform.py +++ b/src/canari/commands/create_transform.py @@ -1,10 +1,9 @@ #!/usr/bin/env python -from common import write_template, read_template, cmd_name, init_pkg - +from common import write_template, read_template, cmd_name, init_pkg, project_tree from argparse import ArgumentParser -from os import path, getcwd +from os import path from re import sub @@ -35,7 +34,7 @@ parser.add_argument( '--transform-dir', metavar='', help='The directory in which you wish to create the transform.', - default=getcwd() + default=None ) @@ -49,6 +48,8 @@ def description(): def parse_args(args): args = parser.parse_args(args) + if args.transform_dir is None: + args.transform_dir= project_tree()['transforms'] return args diff --git a/src/canari/commands/debug_transform.py b/src/canari/commands/debug_transform.py index ae0f017..f2ea3e7 100644 --- a/src/canari/commands/debug_transform.py +++ b/src/canari/commands/debug_transform.py @@ -30,7 +30,7 @@ parser = ArgumentParser( parser.add_argument( 'transform', metavar='', - help='The name of the transform you wish to run (e.g. canari.transforms.nmapfastscan).' + help='The name of the transform you wish to run (e.g. sploitego.transforms.nmapfastscan).' ) parser.add_argument( diff --git a/src/canari/commands/delete_transform.py b/src/canari/commands/delete_transform.py index 6bed264..acbf806 100644 --- a/src/canari/commands/delete_transform.py +++ b/src/canari/commands/delete_transform.py @@ -1,9 +1,9 @@ #!/usr/bin/env python -from common import cmd_name +from common import cmd_name, project_tree -from os import path, getcwd, unlink from argparse import ArgumentParser +from os import path, unlink from re import sub @@ -34,7 +34,7 @@ parser.add_argument( '--transform-dir', metavar='', help='The directory from which you wish to delete the transform.', - default=getcwd() + default=None ) @@ -48,6 +48,8 @@ def description(): def parse_args(args): args = parser.parse_args(args) + if args.transform_dir is None: + args.transform_dir = project_tree()['transforms'] return args diff --git a/src/canari/commands/generate_entities.py b/src/canari/commands/generate_entities.py index 3a8e2a8..3d59812 100644 --- a/src/canari/commands/generate_entities.py +++ b/src/canari/commands/generate_entities.py @@ -1,11 +1,11 @@ #!/usr/bin/env python -from common import detect_settings_dir, cmd_name +from common import detect_settings_dir, cmd_name, project_tree, parse_bool from canari.maltego.entities import Entity from xml.etree.cElementTree import XML from argparse import ArgumentParser -from os import walk, path as ospath +from os import walk, path from zipfile import ZipFile from imp import load_source from re import sub @@ -36,15 +36,15 @@ __status__ = 'Development' parser = ArgumentParser( description='Converts Maltego entity definition files to Canari python classes. Excludes Maltego built-in entities.', - usage='canari %s [options]' % cmd_name(__name__) + usage='canari %s [output file] [options]' % cmd_name(__name__) ) parser.add_argument( 'outfile', - metavar='', + metavar='[output file]', help='Which file to write the output to.', - default='entities.py', + default=None, nargs='?' ) @@ -104,7 +104,10 @@ def description(): def parse_args(args): - return parser.parse_args(args) + args = parser.parse_args(args) + if args.outfile is None: + args.outfile = path.join(project_tree()['transforms'], 'common', 'entities.py') + return args def normalize_fn(fn): @@ -133,7 +136,7 @@ class DirFile(object): def namelist(self): l = [] for base, dirs, files in walk(self.path): - l.extend([ ospath.join(base, f) for f in files ]) + l.extend([ path.join(base, f) for f in files ]) return l def open(self, fname): @@ -144,8 +147,13 @@ def run(args): opts = parse_args(args) + if path.exists(opts.outfile) and not opts.append and not \ + parse_bool('%s already exists. Are you sure you want to overwrite it? [y/N]: ' % repr(opts.outfile), default='n'): + exit(-1) + + ar = DirFile( - ospath.join(detect_settings_dir(), 'config', 'Maltego', 'Entities') + path.join(detect_settings_dir(), 'config', 'Maltego', 'Entities') ) if opts.mtz_file is None else ZipFile(opts.mtz_file) entities = filter(lambda x: x.endswith('.entity'), ar.namelist()) @@ -160,6 +168,7 @@ def run(args): if i.type.endswith('Entity'): nses[i.namespace] = i.__class__.__name__ + print 'Generating %s...' % repr(opts.outfile) fd = open(opts.outfile, 'ab' if opts.append else 'wb') if opts.append: @@ -204,4 +213,5 @@ def run(args): fd.write('class %s(%s):\n pass\n\n\n' % (classname, base_classname)) - fd.close() \ No newline at end of file + fd.close() + print 'done.' \ No newline at end of file diff --git a/src/canari/commands/help.py b/src/canari/commands/help.py index 416b232..39b93a9 100644 --- a/src/canari/commands/help.py +++ b/src/canari/commands/help.py @@ -23,6 +23,7 @@ parser = ArgumentParser( description='Shows help related to various canari commands', usage='canari %s ' % cmd_name(__name__) ) + parser.add_argument( 'command', metavar='', diff --git a/src/canari/commands/rename_transform.py b/src/canari/commands/rename_transform.py index cd3edac..b78dc49 100644 --- a/src/canari/commands/rename_transform.py +++ b/src/canari/commands/rename_transform.py @@ -1,9 +1,9 @@ #!/usr/bin/env python -from common import cmd_name +from common import cmd_name, project_tree -from os import path, getcwd, rename from argparse import ArgumentParser +from os import path, rename from re import sub @@ -40,7 +40,7 @@ parser.add_argument( '--transform-dir', metavar='', help='The directory from which you wish to rename the transform.', - default=getcwd() + default=None ) @@ -54,6 +54,8 @@ def description(): def parse_args(args): args = parser.parse_args(args) + if args.transform_dir is None: + args.transform_dir = project_tree()['transforms'] return args diff --git a/src/canari/commands/run_server.py b/src/canari/commands/run_server.py index 49aff4a..13e6cce 100755 --- a/src/canari/commands/run_server.py +++ b/src/canari/commands/run_server.py @@ -82,7 +82,7 @@ parser.add_argument( parser.add_argument( '--hostname', metavar='[hostname]', - default=getfqdn(), + default=None, help='The hostname of this transform server.' ) @@ -276,10 +276,16 @@ class AsyncMaltegoHTTPServer(ThreadingMixIn, MaltegoHTTPServer): pass +def parse_args(args): + args = parser.parse_args(args) + if args.hostname is None: + args.hostname = getfqdn() + return args + def run(args): - opts = parser.parse_args(args) + opts = parse_args(args) fix_pypath() diff --git a/src/canari/commands/run_transform.py b/src/canari/commands/run_transform.py index 0aefa78..3e1c83b 100644 --- a/src/canari/commands/run_transform.py +++ b/src/canari/commands/run_transform.py @@ -30,7 +30,7 @@ parser = ArgumentParser( parser.add_argument( 'transform', metavar='', - help='The name of the transform you wish to run (e.g. canari.transforms.nmapfastscan).' + help='The name of the transform you wish to run (e.g. sploitego.transforms.nmapfastscan).' ) parser.add_argument( -- 2.45.1